diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 06fd7e4..5af50f3 100644 --- a/.speakeasy/gen.lock +++ b/.speakeasy/gen.lock @@ -1,37 +1,38 @@ lockVersion: 2.0.0 id: b66b7a6c-9758-4aea-950e-ab854bfa8451 management: - docChecksum: 6daf23586aaf993f3a3e87a6211343fb + docChecksum: 6f07aaf0cff71a67fe6cbe7c20de2aa8 docVersion: 0.3.6 - speakeasyVersion: 1.680.12 - generationVersion: 2.788.15 - releaseVersion: 0.3.7 - configChecksum: f1ebdf3558d0ac2e85bd0d3d2282aae5 + speakeasyVersion: 1.706.1 + generationVersion: 2.809.2 + releaseVersion: 0.4.0 + configChecksum: 8feda5d705ac78c61dffe8a974a13295 repoURL: https://github.com/OWASP/nest-sdk-python.git installationURL: https://github.com/OWASP/nest-sdk-python.git published: true persistentEdits: - generation_id: d9f2c755-b3f8-4440-8629-be40fb0f357a - pristine_commit_hash: 401ef80d7f40280146806457319554506db529c9 - pristine_tree_hash: 6dca6e532147d222f89d68461d3f849b3e8310f6 + generation_id: e9a2384a-db6e-4232-a21a-03705816fb1b + pristine_commit_hash: 35e9429347af91f57c9cd5156ae0190bccac3f30 + pristine_tree_hash: 7a696b1ad13b4a149b1959b99f11ba9ce62c54d7 features: python: additionalDependencies: 1.0.0 - constsAndDefaults: 1.0.5 - core: 5.23.15 + constsAndDefaults: 1.0.6 + core: 6.0.3 defaultEnabledRetries: 0.2.0 enumUnions: 0.1.0 envVarSecurityUsage: 0.3.2 flattening: 3.1.1 - globalSecurity: 3.0.4 + globalSecurity: 3.0.5 globalSecurityCallbacks: 1.0.0 globalSecurityFlattening: 1.0.0 globalServerURLs: 3.2.0 methodArguments: 1.0.2 - nullables: 1.0.1 - responseFormat: 1.0.1 + nullables: 1.0.2 + responseFormat: 1.1.0 retries: 3.0.3 - sdkHooks: 1.2.0 + sdkHooks: 1.2.1 + unions: 3.1.2 trackedFiles: .gitattributes: id: 24139dae6567 @@ -69,14 +70,18 @@ trackedFiles: id: cd2417939762 last_write_checksum: sha1:8f4e4b59c9b338637618d42fdf2952f421933863 pristine_git_object: 10e261f29c34c15eae09f4999cb58d2eb4c62a72 + docs/models/errors.md: + id: 09a4da1e2f9e + last_write_checksum: sha1:31a2d400b544a286d3aaa224ee996273b5ef8167 + pristine_git_object: fc1e63cb5a28f8dea23f218ae6171ed693633eab docs/models/event.md: id: 311c22a8574a - last_write_checksum: sha1:ba71d42122012ec3c4e73fb843af493015c6ad24 - pristine_git_object: bdcc81134eaa5740009bf9cc91a4e13189d9e135 + last_write_checksum: sha1:4badb5723ca4b8c4bfabb0a3af70afe1f8e17bbc + pristine_git_object: 75d4000fe2639ab3129304a66f18d10c789191a4 docs/models/eventdetail.md: id: 09b6b6b2a01e - last_write_checksum: sha1:920e86a126655c5f11bc9d466944a372ea659902 - pristine_git_object: e31b0520e34e78f608b0258d7653f2a6aa8f57fc + last_write_checksum: sha1:32eaf516b515780050d077ee16ec057fa0533616 + pristine_git_object: 40f502a4474515ea3d7cc17f6b76a74a420323a4 docs/models/eventerror.md: id: e011839176d0 last_write_checksum: sha1:d2bf6347ba353834b595b8af991b1542e11e3bcc @@ -207,8 +212,8 @@ trackedFiles: pristine_git_object: edf7eb6c8d697b2842101c9496a8744c0217d7cb docs/models/listprojectsrequest.md: id: 733f20d8500a - last_write_checksum: sha1:3e470713a7f5bc4a92084c319a5a1b344ecaf3d3 - pristine_git_object: c0bcfceae375aea7981be75b7cfad88068ea262f + last_write_checksum: sha1:a7d200b94b8202741c5f42bdd8f023eb9f9b8595 + pristine_git_object: bfc08309549d51b8c12a2879d7196c4d726c0e83 docs/models/listreleasesordering.md: id: 41412692fbee last_write_checksum: sha1:8faa305f3ac47122d342f01ead17a790681d96ec @@ -461,58 +466,62 @@ trackedFiles: id: 4343ac43161c last_write_checksum: sha1:562c0f21e308ad10c27f85f75704c15592c6929d pristine_git_object: 69dd549ec7f5f885101d08dd502e25748183aebf + docs/models/validationerrorschema.md: + id: 37f844776f39 + last_write_checksum: sha1:4ca4f60313fd832375963e5416eca7af1771cf39 + pristine_git_object: 3ad353df046175ccc97151f27559fd199ce3ada6 docs/sdks/chapters/README.md: id: b545e9645ae9 - last_write_checksum: sha1:09bdae0edbd3dd5f8bac4af411f1bd2002301b2c - pristine_git_object: 75f0ff1abc057de7c6fdfe8afef19f3a19d878ea + last_write_checksum: sha1:6e61c9a1a8b96be3bc29b4df6a80441fd04abf73 + pristine_git_object: ab778c649dd949dbbe58a67ec9908ab2f0c97b9e docs/sdks/committees/README.md: id: 3283fa74455b - last_write_checksum: sha1:5f7968bd57779c0c5b0e8b8af78abe56a76dfc7a - pristine_git_object: 86e7763fd7fb64096820913cdc9a7e63706e1d21 + last_write_checksum: sha1:3ecbd73960f1dee0f4c37faf67552ce17b9c3e84 + pristine_git_object: 03c6a9802b5f2a7e02125b615a4f11f8de53117b docs/sdks/community/README.md: id: 529704b7cfa8 - last_write_checksum: sha1:5e27b0d80a44f5cdc4bf9fc908ae5599965743bd - pristine_git_object: 83e475ab413de3693902e4e8e2328cc8275a651e + last_write_checksum: sha1:9d4d116280cec83205e5d45aad55215b8c9ed8fb + pristine_git_object: a293e0769915f0da0082d573a17e56cb0bcbf28c docs/sdks/events/README.md: id: cf45a4390b9b - last_write_checksum: sha1:4a517e8d1e2cffab3569245855b40069c819da9c - pristine_git_object: 40d919b7cab30c61fb7d24acc13480063a8a476f + last_write_checksum: sha1:486ec0866cb71db578a1c1a27017968c79419b00 + pristine_git_object: 6abab198f0a16c30fce99b03e3104891b9dd68bb docs/sdks/issues/README.md: id: cbb80cd6efef - last_write_checksum: sha1:30afd9ffbe72c4970bb27ee82312fa5c3fa5e703 - pristine_git_object: 6bed2113c8910105b36e5ede90ac0a7227dfc7fe + last_write_checksum: sha1:caf3a7e280d84ecbe3366765f0b3744028ceafca + pristine_git_object: 7a27723460b46a6938b838ccf02b8c60cb1b0a5e docs/sdks/milestones/README.md: id: 186be158f715 - last_write_checksum: sha1:95382a4a5c7faa59775b128b7bede8b834e6177b - pristine_git_object: d1ca1093818e3489a3e992644a3c48ab65b7b0c1 + last_write_checksum: sha1:cddd3b68d90df49714339d9b874c496021712ad7 + pristine_git_object: 79eb897269b15349712e236ffcb3cad2c1d5752c docs/sdks/projects/README.md: id: 1c5f71754e17 - last_write_checksum: sha1:faf8ef706233723ad9a4c3a131af2116f30f465d - pristine_git_object: be9aa1dcb2ededbed1bded24a8e6c5eeb040e796 + last_write_checksum: sha1:0ce43cdf96e6c2a791a3f3488102ef4c5e897209 + pristine_git_object: 892ad3122f70875aec1eb0463d602df3bc0b0b76 docs/sdks/releases/README.md: id: 63d3c821dfd3 - last_write_checksum: sha1:769caa804b1c389264be50b0ce35d2f1fc5a260b - pristine_git_object: 6776572c536fe7237cef2eae43232b6946b0afd9 + last_write_checksum: sha1:164f93c05b2bd33c0c1a43471524e3551b4320f8 + pristine_git_object: e5995ccec44304dc51de8301354d2a8869aad072 docs/sdks/repositories/README.md: id: 67c85cb3c692 - last_write_checksum: sha1:9274121d303acd7df3005e99326856bf8158f6c4 - pristine_git_object: d18def6b27fc9a839f4407233c8a78d84d36cad4 + last_write_checksum: sha1:0462ae33e452aec7b3d127d821468fb6c5011ad7 + pristine_git_object: d3cdb2d8c3dc4e70bee9c2e4a7f6c33bb7ebb487 docs/sdks/sponsors/README.md: id: c91dd0ddc795 - last_write_checksum: sha1:62b4cf9b7e9c7ce5d07b6d349c2e4f22a0124d2e - pristine_git_object: a3c0bfc333d18bb12d4100b0cdf2a2f59efb5a4b + last_write_checksum: sha1:6dc66b6e3760f4dc062d2eb809bfdc44590ea9dc + pristine_git_object: 334976d386eec001b3f359cac964ace72b7ffdb5 py.typed: id: 258c3ed47ae4 last_write_checksum: sha1:8efc425ffe830805ffcc0f3055871bdcdc542c60 pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544 pylintrc: id: 7ce8b9f946e6 - last_write_checksum: sha1:d99516d03b4492a038ef908be7aa202d914d1dcf - pristine_git_object: 7f1dd32e8a5a3c2c02519af121a88dd2988dd308 + last_write_checksum: sha1:fbeac447498dbcb802414ab89db64a1a2438dc8c + pristine_git_object: 2dc74cb274c9da383e0d0fa4a88b4aa6b2e0e092 pyproject.toml: id: 5d07e7d72637 - last_write_checksum: sha1:59528a34db3298750d781e06d35144162b323b9c - pristine_git_object: 448a509f4e80115b8bd9cef8177802f0068186ac + last_write_checksum: sha1:c29031487b5dd6b3b24ec3edb779a33fa161da80 + pristine_git_object: 08d2eab670e2ce9626e6df6af22bedb3f25611ff scripts/prepare_readme.py: id: e0c5957a6035 last_write_checksum: sha1:c87a34a7b385c45d801ea4570aaed5b8e12eeac3 @@ -539,52 +548,52 @@ trackedFiles: pristine_git_object: 336908e19d943edcc6d49482de0d61f40197e2ae src/owasp_nest/_version.py: id: 36e8ce475baa - last_write_checksum: sha1:39015e0e023a1ff705107dd266d779793caab813 - pristine_git_object: 0052f637296db71efc081bb9ea5b1e06aa0a5fc9 + last_write_checksum: sha1:81c9236b33465898516471ce9e83a276846152ed + pristine_git_object: eb92b10a3a2d34491399164f28ac69924e26093a src/owasp_nest/basesdk.py: id: 9727edc94589 - last_write_checksum: sha1:0008b3c8803bdb08693a6c2f63ad52ccf400bd18 - pristine_git_object: 65969ec8c97f2e237bbe8b8952bb60dcffe10deb + last_write_checksum: sha1:d9f028124fcc32fe95daa57fbc931178f10fb670 + pristine_git_object: 7367babbc2b3d7b380ab6778999c78d2ba6f6b39 src/owasp_nest/chapters.py: id: 59b0f20f3236 - last_write_checksum: sha1:e67fff16d483c58c74ac10f9221c24bade3ca5e2 - pristine_git_object: f89cdae669df82d31da5ff040c8150e7c722f454 + last_write_checksum: sha1:23f4134dc24e93a2374953156e38bfcc3b5f0049 + pristine_git_object: 1cd1216ba143f03e48ac83f4cea8205a0e8828b6 src/owasp_nest/committees.py: id: 7c607767be32 - last_write_checksum: sha1:da04810cd61499b3b80eaadf2c94226cb302175c - pristine_git_object: 341b5f6a842f94a632875c87407fb1725914c24b + last_write_checksum: sha1:5a73962dfaa439d0cb8eca8dfc26bb9672f1ba51 + pristine_git_object: c87850206e6b4b68737afbab2e65efa5bbb3d0a1 src/owasp_nest/community.py: id: 87b178185cc3 - last_write_checksum: sha1:af117d70d4737e52f259a466f221aef63e905ba3 - pristine_git_object: 459b5b7381d51c8a4fc042b32940d2c7ca072e02 + last_write_checksum: sha1:dc82dd1c9dbf9b0c7d51a60106a0538f5bf0287d + pristine_git_object: 46c74072ce7d9da520a4048bbc44f027f3d32fcd src/owasp_nest/events.py: id: 9e6250bd35e0 - last_write_checksum: sha1:81854e4df377fc9b989cdb70e0854d634bf29a05 - pristine_git_object: b2081f23e74c3b8aa1afc5773c10def7ce2b407f + last_write_checksum: sha1:0570dee4971d991fc56c81f9e9d50d41a5200dd7 + pristine_git_object: 048637127291dff2109a2817c533ee78afb87ae2 src/owasp_nest/httpclient.py: id: b78cee027f40 last_write_checksum: sha1:5e55338d6ee9f01ab648cad4380201a8a3da7dd7 pristine_git_object: 89560b566073785535643e694c112bedbd3db13d src/owasp_nest/issues.py: id: 7d52443cd259 - last_write_checksum: sha1:346a4281b176c29654fac74d1e4db2c275edafaa - pristine_git_object: f2ad9e19efa90dd597e26f5686f3963ca3b943fd + last_write_checksum: sha1:3fce9f56d7375d607b7b6c4fbf41545fa08e2cb6 + pristine_git_object: c86e7a137a5c499f58ccc948052ade79b9f845f0 src/owasp_nest/milestones.py: id: 898e390a8a3e - last_write_checksum: sha1:a3d627ed9cde183df1450c8410fc590e32084eeb - pristine_git_object: c448fad7c5bae27e8bec82abbdcbc0d34ba48ddb + last_write_checksum: sha1:6bfbe7de7bdbe6d48e497788f48e990fe35c231f + pristine_git_object: c8d1725b2e5d613d267b7aeb4c485433cad44176 src/owasp_nest/models/__init__.py: id: 4bb3871d870f - last_write_checksum: sha1:cb5eb1846a6510bd1ac870b673587e15baba4f1c - pristine_git_object: a01eaf4e6ae4046b6b45d2b6557f234702b8e60a + last_write_checksum: sha1:4352f122a840fc4b3ccb88947ed7e656d989a9d1 + pristine_git_object: 7884bb36214f8ceb3d173de2bcf80c0b2880a485 src/owasp_nest/models/chapter.py: id: 8e8245c44d00 - last_write_checksum: sha1:21348575eb9ac31290c446cfbf604b5b039da991 - pristine_git_object: ee2af8df6b2375e42f805a959ba1b5a9be425797 + last_write_checksum: sha1:1a218e20197633c423d5fe2eb80d177f0575f9b7 + pristine_git_object: 32eea353974cda10828c095df93233ba9c217db6 src/owasp_nest/models/chapterdetail.py: id: c6787bf512e8 - last_write_checksum: sha1:0c34751d0f087ff549924085da4c650f10a629a6 - pristine_git_object: 0f5773f430200d38718ab5c0de09b7c615f9be31 + last_write_checksum: sha1:5bd030eca74cf987176e22fd3a5291a4e46148a0 + pristine_git_object: 697013a40a96641701e2ee054567511be9992a14 src/owasp_nest/models/chaptererror.py: id: 636caa279a71 last_write_checksum: sha1:76838ea0ee0a6be39ef1f6c9d99a0ce235cc4d14 @@ -603,12 +612,12 @@ trackedFiles: pristine_git_object: 5ec48cf6b5b411e039b21167d4900450c9fbb612 src/owasp_nest/models/event.py: id: 7784af6ad371 - last_write_checksum: sha1:963e3c1d23ddbb9970d2c9506668e455e2333622 - pristine_git_object: 25a63af77525a6cdc4142bf4d9388da470042c2c + last_write_checksum: sha1:62fba14c300e9e92b1fbc505de81d2cf6b0b9e0c + pristine_git_object: dc0159a6e26e3a5a1a7a0996cf3132bf8da2acbd src/owasp_nest/models/eventdetail.py: id: da3d4b6c2062 - last_write_checksum: sha1:2776a091040abab873b55d5becff0dd7131c90a0 - pristine_git_object: 9f4f1406afb62463021d21b3fe205507a854cead + last_write_checksum: sha1:e7047feaa9d3cb6e74de2a706559a88757cb779d + pristine_git_object: a7cd90dafe580664b829c2f13bff34e7706acc74 src/owasp_nest/models/eventerror.py: id: 276621381a00 last_write_checksum: sha1:bb7fe65d87daebba4411cd7287efde96c50dffc6 @@ -675,76 +684,76 @@ trackedFiles: pristine_git_object: dfa7271865d3c68195420acc6b4bb33ed3f72787 src/owasp_nest/models/leader.py: id: a258771798e6 - last_write_checksum: sha1:e0d78a76b9c44ee7aaf86abbab05d92a47c7e5db - pristine_git_object: a32391722bd3799d69dea45ff4b44a2b95a90b2c + last_write_checksum: sha1:cb7c7b3cea57f9b8197ad0bd18df13d35e64cc48 + pristine_git_object: cf80675fd9fa20fbde096061ce47eb53f5464269 src/owasp_nest/models/list_chaptersop.py: id: ceba59007274 - last_write_checksum: sha1:966e0c0a2d46d6390866622ab3a9bec9c88e655f - pristine_git_object: b78e55892b26225743db31723bf14c7d8745fa28 + last_write_checksum: sha1:f502d2d4a4087f99f4cfe9ad2fa973752a42b3f1 + pristine_git_object: 2dbee21dfeb2bbb24ba1c0b32bb322c3344e4d9f src/owasp_nest/models/list_committeesop.py: id: 096fdebee6ee - last_write_checksum: sha1:a79cc72163438a76c23b4cea9e3d6e63f88584be - pristine_git_object: c65153b1389dfd98a07c4e69a0d4e3fe4c7be668 + last_write_checksum: sha1:750983b9b792f0f1d5da0b6a785137ad0ef91619 + pristine_git_object: 82b14739cb9fcb1e234c611942d56a1c65023a41 src/owasp_nest/models/list_eventsop.py: id: 7b8ec6af956d - last_write_checksum: sha1:65e6a387c9604041ab5390cdeea8a9224231c2d8 - pristine_git_object: 042bf641b42922907e1c646911ba99e9ca7e62d0 + last_write_checksum: sha1:1084a6a47378514f2a9edce5e2c42da0070b2094 + pristine_git_object: 182e6041e06bca3ec3f20ced71d30ea6652238cf src/owasp_nest/models/list_issuesop.py: id: b5894fd7eb8d - last_write_checksum: sha1:3309512e7e45e7f200312f5eec776037f341b8f4 - pristine_git_object: 7e7e19fbdc83c476435794b0b6aeeb26545451b9 + last_write_checksum: sha1:c16f40711e86870cea26d646383b68d0118cf73c + pristine_git_object: e1e0cc996001b8612039ad31d9c130f560cb4e03 src/owasp_nest/models/list_membersop.py: id: 2850d40ffb12 - last_write_checksum: sha1:b21b280dd1a6ea29a651af444e1d6d06f2604cbb - pristine_git_object: e73cfe618e0a1e7902bebe7718f0a8311859a56c + last_write_checksum: sha1:322a3ab7890a508f8db245765ecba0f87f7010de + pristine_git_object: 989e39a27957e60a51e98e8145e666706fd6b65a src/owasp_nest/models/list_milestonesop.py: id: a7d5235d4f53 - last_write_checksum: sha1:7cd2f90d065a7de26aa9d6758c76ebf176f62308 - pristine_git_object: 47d1c96dc1ad93f99e7398d16d3796fd6be72101 + last_write_checksum: sha1:0d539a73bea014fd118df7580f4c02adb89d733d + pristine_git_object: 9222723f5e0071bdc444579df9e3a46933b13b52 src/owasp_nest/models/list_organizationsop.py: id: 4d7ae48b4f1e - last_write_checksum: sha1:f263198f8efae9380ee76f15803e9e1a3cb525a0 - pristine_git_object: e5da7ad3f6702a1baa6d6d26a8789e15c9d87fbe + last_write_checksum: sha1:fc4686392f6316fc888d15753722e37124751f93 + pristine_git_object: 417e0dc56f3ea671492b09bc85cc117edc6e351e src/owasp_nest/models/list_projectsop.py: id: 9ea6e92bba04 - last_write_checksum: sha1:3b8cce2468d80dddc754bee380d982f49e99ec51 - pristine_git_object: 12233f0d18c57454882b57dcfb85fca7e4b3bb9e + last_write_checksum: sha1:83bb9963dcb5c541c2e9abf029064307491ddab5 + pristine_git_object: 2fb762154f431132e0df45a7789a10d5198c711a src/owasp_nest/models/list_releasesop.py: id: 29aab0b4a829 - last_write_checksum: sha1:ea41166ba2fc5e70fa1234918e5517bb42707b88 - pristine_git_object: 135973cff151e366b4a1269b76d6be4d80e26f78 + last_write_checksum: sha1:9cc15d7bd8b4efc583d4d13c7d0748f7580fb3e6 + pristine_git_object: a55e884769436b203b537c5449efd433f6cf90be src/owasp_nest/models/list_repositoriesop.py: id: ed77c79c9ccc - last_write_checksum: sha1:1b81cb723caea82906260f3baf4b65e883b7ea86 - pristine_git_object: 08e0687215248e5ba2d9a663698fd5fbc243ba83 + last_write_checksum: sha1:8c78cb148a22f2de853bb125d99f69702ece82d9 + pristine_git_object: 1a1c5a713d94fbb7997982ec53def61e52ba02fc src/owasp_nest/models/list_snapshot_chaptersop.py: id: c1910f618109 - last_write_checksum: sha1:9fee295016fa2d83637cf55437d4cc53da10276e - pristine_git_object: d54a824a4788b947f5cee40f8c5fc4d43e128cb1 + last_write_checksum: sha1:40ced3fc53c06b500dffb71fd663b0e26b87b052 + pristine_git_object: 76df0979391f505c5b1f78fa6bbf050bf3cb3a2d src/owasp_nest/models/list_snapshot_issuesop.py: id: f196f51aa762 - last_write_checksum: sha1:88a519ffdbfa5ab0df846af9c2e7018dc4bf6421 - pristine_git_object: 9d8f8c35b434ae9d4d005a26d2a64ba7cfc6c9fc + last_write_checksum: sha1:4134cd372f146497e9751ac4afd55acafa1dba1b + pristine_git_object: 35052aa1b33c157fc54169fa41474f8e27e38fc5 src/owasp_nest/models/list_snapshot_membersop.py: id: 8a9d9dd9a264 - last_write_checksum: sha1:37c991401db611e40c672b06d2247560d83c1d4f - pristine_git_object: 337497b39d9242728c6d2308ad1d52871c4ea0ec + last_write_checksum: sha1:ad671bfac726de572a5c5f4d8b5488fe54c4a8d1 + pristine_git_object: 2a8583bc39d501db269100f91fedbe57569c2f31 src/owasp_nest/models/list_snapshot_projectsop.py: id: 273e23f1e2c1 - last_write_checksum: sha1:2a8a35d19c616ae22b73f57660535c6449e0b696 - pristine_git_object: 6849718ac29a0ff8bd7433d70ce74f45978e7b17 + last_write_checksum: sha1:9115a2790b2464b6391c7c92a8c6ea56aa2d630b + pristine_git_object: b63f5e7d8921429775111e36e19887d8eda71807 src/owasp_nest/models/list_snapshot_releasesop.py: id: 2b5cf6f45f52 - last_write_checksum: sha1:efd4e4a737ad902ae33126009dac2a1e0edb05e3 - pristine_git_object: 3d32d67a912d89aebeb0c6b9f9a1f0d00754f2b0 + last_write_checksum: sha1:d32dffc8653521fdca413e7d608d7d7b522cfe86 + pristine_git_object: 8f3314d5b62dbcf1cd73d3ac9724a969e8d0701e src/owasp_nest/models/list_snapshotsop.py: id: 4e88ef87cdef - last_write_checksum: sha1:f9238c757e1d47931bbea84cf8cb5330821c7cd6 - pristine_git_object: 270c932b6937abbb6cf735477df4870ecd0ffde4 + last_write_checksum: sha1:77a83488eb100fa02d88b68de78e37083aef99d0 + pristine_git_object: 99f2f4120ccccf14596590d3242d92ee7e0bc99e src/owasp_nest/models/list_sponsorsop.py: id: cca2df8e1670 - last_write_checksum: sha1:78955e73cb77c03fd1b3ceb1309ed6488a6349f0 - pristine_git_object: 5187dc752ecf8412078bd28553fd237173ac40e9 + last_write_checksum: sha1:1ae067883119a1ef90c6c3390b8ecfffde458640 + pristine_git_object: 3353fb0ba91b9e1aadfbb563c9e4122c62402009 src/owasp_nest/models/member.py: id: 8166aff17ff1 last_write_checksum: sha1:9805a9c03562c11928f83547daa9c33110fbc7a2 @@ -767,8 +776,8 @@ trackedFiles: pristine_git_object: d0a33871cee4a6c2d76d3c6926bdb5a4104b68a3 src/owasp_nest/models/milestonedetail.py: id: 835fc0c5d127 - last_write_checksum: sha1:237cf5ae5622b6e8111c48e3fa8147cfa5b244cb - pristine_git_object: 928283a602f00e35f9be35eeeca64ae9ae55c4a6 + last_write_checksum: sha1:37a2c0274fdbc1bd6827997f29ba885e21bb31cd + pristine_git_object: 170f67ea04b0688b49dec6c2b726923e580857ee src/owasp_nest/models/milestoneerror.py: id: bdce646af95b last_write_checksum: sha1:6a4e181a9e012c09b236287b5992064b4f024a10 @@ -871,12 +880,12 @@ trackedFiles: pristine_git_object: d459a8c5a7421c8e34733342eae51e00d5372e4b src/owasp_nest/models/release.py: id: e9f78d9ffd3f - last_write_checksum: sha1:e68e86c43364427904f00c9a1b2fbfbe3e82b35e - pristine_git_object: fd82e37816425059ca3a945bd1070c311a4de8d5 + last_write_checksum: sha1:e710693f8457393f2c5e30905127a90fff8e324e + pristine_git_object: 0449dbf9b5a398834d5e616e6ddc1cf8d6aa1af0 src/owasp_nest/models/releasedetail.py: id: 0ab8ef85f47a - last_write_checksum: sha1:5fb6bc439e6dced3bb0146ca51dea37bef5b34fa - pristine_git_object: 0c7ea937d22aa55d79b14891eaf27b2aefb0dd0f + last_write_checksum: sha1:1773d5680bb800290cf16ec333c59c285485d7f1 + pristine_git_object: f478c0232dd35d5ef15f021e61339ce70115e591 src/owasp_nest/models/releaseerror.py: id: 9ce853cae08d last_write_checksum: sha1:ef643815b9478b179588e20d86f62187ad8f6168 @@ -887,8 +896,8 @@ trackedFiles: pristine_git_object: bba10c7f07a0526fd63849d27b2f28fa70ed8440 src/owasp_nest/models/repositorydetail.py: id: 7fc5bbbfce2e - last_write_checksum: sha1:82feae76bb913bd05ad2f924db7f1dda80fff1ef - pristine_git_object: 1998ff0cba3ca57b83c451401acc1ba6b0932bf6 + last_write_checksum: sha1:f43873c0dafb90a70fd305b2d30b913aecb2830c + pristine_git_object: 88c814c63b41f657e09958a8553d2325e700e224 src/owasp_nest/models/repositoryerror.py: id: ca73ff71a5d7 last_write_checksum: sha1:fa9b1c06408df9461d3fda6454bb944570394c9b @@ -915,12 +924,12 @@ trackedFiles: pristine_git_object: ab350acbba6b0f06b5acc5a570e287ec3eacfed6 src/owasp_nest/models/snapshotissue.py: id: 0de2af101a67 - last_write_checksum: sha1:c942e44e14e1c520332e8e4a8949832056560e3a - pristine_git_object: 3037f4591168f44c1706a3544588a7cf2ef64e67 + last_write_checksum: sha1:508a989ca8e3272fd6ab7deccb66bd8ba611bd3d + pristine_git_object: 558e0d3a5819567bf76a42efd94185d9ec9241ad src/owasp_nest/models/snapshotrelease.py: id: dec2f7cc42ae - last_write_checksum: sha1:ab715802dc514ea916d04329fd94944e86712bc5 - pristine_git_object: 5af7ddc11c54f0859ae849cf8b6c1e50858a4cd5 + last_write_checksum: sha1:6723ed155f1ed81d16c47366eaf774eab0e2f096 + pristine_git_object: 12b54836bac97eae32e3a2ea6d9b95e3e3d8fb71 src/owasp_nest/models/sponsor.py: id: fb2f12c32fad last_write_checksum: sha1:398e7826e808dc0ffd618baa1a2f71e49d94aacd @@ -937,22 +946,26 @@ trackedFiles: id: a23ca73ec239 last_write_checksum: sha1:48744cebd712a128eab1298434ce389452f9d8d9 pristine_git_object: 5cd04ec5f078bb79aec8af2c67e51463165f2d6b + src/owasp_nest/models/validationerrorschema.py: + id: 8485a665ab8c + last_write_checksum: sha1:2507b5d988d66328ca174ab6ff2ee6ff0c4f4a42 + pristine_git_object: ab9e722b159949961be9b8a2cee25374e8398231 src/owasp_nest/projects.py: id: d9cc138704c2 - last_write_checksum: sha1:c79a1048abc8de72354709943039c669b5d6e2ad - pristine_git_object: cf428b119629b8e0faa3fac22b47ac385c8833b8 + last_write_checksum: sha1:0367b7a49b46120cf765359faf3dc1d3ae3ae51d + pristine_git_object: 825ed285b1fbf4db8a5413051607bd2ed84b0685 src/owasp_nest/py.typed: id: 93c27d15655e last_write_checksum: sha1:8efc425ffe830805ffcc0f3055871bdcdc542c60 pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544 src/owasp_nest/releases.py: id: d1ded8fcbd22 - last_write_checksum: sha1:154b3a5cdd173c79dbdf2414d319fb96984a2cfb - pristine_git_object: 5aab1f241f2d646bdb653ef4b0da12d367ff3fbd + last_write_checksum: sha1:06e8cb5ef3302a6502124922b65e1e594f3c58be + pristine_git_object: e528147cdd808fa2a676f5adfb5058d7961786db src/owasp_nest/repositories.py: id: 9a84534b0fa1 - last_write_checksum: sha1:6197acd906bc4cc4d10dad8c0bfaaf6379383579 - pristine_git_object: 344fe7e320beada4dedbec3ecb2a310d052c1c52 + last_write_checksum: sha1:099b2ed662ed00fd9f50af1e3cdf7e3e8505d9e5 + pristine_git_object: 735aeb3b2c869ff1e7a1ddce9b05f2a572a378ae src/owasp_nest/sdk.py: id: 1ca4fb7a4b6f last_write_checksum: sha1:c5a3633aae2e0334b85cdfbe85f5227a18f3f46e @@ -963,20 +976,20 @@ trackedFiles: pristine_git_object: a24e0b3cdcb470b8b334c7f5d0d4af6fddd684ca src/owasp_nest/sponsors.py: id: 8b06cbb113d1 - last_write_checksum: sha1:92fa910df09abe08a119e200184f6b56d4ed921c - pristine_git_object: d449257390b6ece55c57077f2bb44be2a1a0d03c + last_write_checksum: sha1:473bef9002eb1b4f36ff88d3d2c61e77c08eac4f + pristine_git_object: a9ebc679656d3c9cbce92ba232fbc43d2923169d src/owasp_nest/types/__init__.py: id: e2cb7bb3aae2 last_write_checksum: sha1:140ebdd01a46f92ffc710c52c958c4eba3cf68ed pristine_git_object: fc76fe0c5505e29859b5d2bb707d48fd27661b8c src/owasp_nest/types/basemodel.py: id: c76ebb8a6831 - last_write_checksum: sha1:615d0b364fa924b0fef719958df34596cc7c1ae2 - pristine_git_object: 231c2e37283a76082f1a064c7aae47f8ee4ee694 + last_write_checksum: sha1:10d84aedeb9d35edfdadf2c3020caa1d24d8b584 + pristine_git_object: a9a640a1a7048736383f96c67c6290c86bf536ee src/owasp_nest/utils/__init__.py: id: 63b65876a55a - last_write_checksum: sha1:81e0385b93362e0f3f6911b65bd4cc601ebc11e1 - pristine_git_object: 56164cf3a86399ee7a8e1a68d19fb494689d77c3 + last_write_checksum: sha1:a1f6ae620fb6a3ccc30e99b427e49a0c8be463af + pristine_git_object: 15394a08a7e30033d319e44dd5734664ddb587e5 src/owasp_nest/utils/annotations.py: id: b0f45ad0a72c last_write_checksum: sha1:a4824ad65f730303e4e1e3ec1febf87b4eb46dbc @@ -987,12 +1000,12 @@ trackedFiles: pristine_git_object: a6c52cd61bbe2d459046c940ce5e8c469f2f0664 src/owasp_nest/utils/enums.py: id: ab6b0560ccdc - last_write_checksum: sha1:786ba597f79dca6fbc0d87c591752bb8d775ecb7 - pristine_git_object: c3bc13cfc48794c143a64667f02e7949a8ce3fcc + last_write_checksum: sha1:bc8c3c1285ae09ba8a094ee5c3d9c7f41fa1284d + pristine_git_object: 3324e1bc2668c54c4d5f5a1a845675319757a828 src/owasp_nest/utils/eventstreaming.py: id: bcd915c02fc2 - last_write_checksum: sha1:bababae5d54b7efc360db701daa49e18a92c2f3b - pristine_git_object: 0969899bfc491e5e408d05643525f347ea95e4fc + last_write_checksum: sha1:ffa870a25a7e4e2015bfd7a467ccd3aa1de97f0e + pristine_git_object: f2052fc22d9fd6c663ba3dce019fe234ca37108b src/owasp_nest/utils/forms.py: id: 6612dbcd058c last_write_checksum: sha1:15fa7e9ab1611e062a9984cf06cb20969713d295 @@ -1015,20 +1028,20 @@ trackedFiles: pristine_git_object: c04e0db82b68eca041f2cb2614d748fbac80fd41 src/owasp_nest/utils/requestbodies.py: id: dcec4fe6279f - last_write_checksum: sha1:e0a3a78158eba39880475d62d61be906625676b8 - pristine_git_object: d5240dd5f5efffabbd9aefa2f4a349511a9c75b4 + last_write_checksum: sha1:41e2d2d2d3ecc394c8122ca4d4b85e1c3e03f054 + pristine_git_object: 1de32b6d26f46590232f398fdba6ce0072f1659c src/owasp_nest/utils/retries.py: id: 46b443354647 last_write_checksum: sha1:5b97ac4f59357d70c2529975d50364c88bcad607 pristine_git_object: 88a91b10cd2076b4a2c6cff2ac6bfaa5e3c5ad13 src/owasp_nest/utils/security.py: id: b73cd3bb41e8 - last_write_checksum: sha1:a17130ace2c0db6394f38dd941ad2b700cc755c8 - pristine_git_object: 295a3f40031dbb40073ad227fd4a355660f97ab2 + last_write_checksum: sha1:435dd8b180cefcd733e635b9fa45512da091d9c0 + pristine_git_object: 17996bd54b8624009802fbbdf30bcb4225b8dfed src/owasp_nest/utils/serializers.py: id: 324ef64abe6e - last_write_checksum: sha1:a0d184ace7371a14a7d005cca7f358a03e3d4b07 - pristine_git_object: 378a14c0f86a867ca7b0eb7e620da82234c0ccc4 + last_write_checksum: sha1:ce1d8d7f500a9ccba0aeca5057cee9c271f4dfd7 + pristine_git_object: 14321eb479de81d0d9580ec8291e0ff91bf29e57 src/owasp_nest/utils/unmarshal_json_response.py: id: 982417b892db last_write_checksum: sha1:0121fbebae65971e2608d0b3097e7bfb8dfbe8d7 @@ -1164,6 +1177,8 @@ examples: application/json: {"created_at": "2024-10-15T07:48:29.830Z", "key": "", "name": "", "updated_at": "2023-12-24T21:08:33.483Z", "country": "Hungary", "leaders": [], "region": ""} "404": application/json: {"message": ""} + "400": + application/json: {"message": ""} list_members: speakeasy-default-list-members: parameters: @@ -1185,6 +1200,8 @@ examples: application/json: {"avatar_url": "https://winged-help.net", "created_at": "2024-03-25T14:53:31.200Z", "login": "Rodolfo.Lindgren", "name": "", "updated_at": "2023-12-31T23:08:06.768Z", "url": "https://yummy-colon.org", "bio": "", "company": "Jacobson and Sons", "followers_count": 877273, "following_count": 836968, "location": "", "public_repositories_count": 289203, "title": "", "twitter_username": ""} "404": application/json: {"message": ""} + "400": + application/json: {"message": ""} apps_api_rest_v0_chapter_list_chapters: speakeasy-default-apps-api-rest-v0-chapter-list-chapters: parameters: @@ -1279,6 +1296,8 @@ examples: application/json: {"created_at": "2024-10-26T15:58:22.888Z", "key": "", "name": "", "updated_at": "2024-10-23T09:23:37.658Z", "description": "phew regal hoarse what tedious pharmacopoeia stealthily disadvantage emergent at"} "404": application/json: {"message": ""} + "400": + application/json: {"message": ""} get_organization: speakeasy-default-get-organization: parameters: @@ -1289,6 +1308,8 @@ examples: application/json: {"created_at": "2025-12-12T04:28:03.547Z", "login": "Alessandra_Beer", "name": "", "updated_at": "2023-07-11T13:29:35.567Z", "company": "Padberg - Hettinger", "location": ""} "404": application/json: {"message": ""} + "400": + application/json: {"message": ""} get_project: speakeasy-default-get-project: parameters: @@ -1299,6 +1320,8 @@ examples: application/json: {"created_at": "2023-03-06T09:23:19.829Z", "key": "", "level": "lab", "name": "", "updated_at": "2023-12-06T04:15:58.999Z", "description": "since limply gah consequently ugh petticoat wholly possible", "leaders": []} "404": application/json: {"message": ""} + "400": + application/json: {"message": ""} list_sponsors: speakeasy-default-list-sponsors: parameters: @@ -1320,6 +1343,8 @@ examples: application/json: {"image_url": "https://enlightened-hunger.info", "key": "", "name": "", "sponsor_type": "", "url": "https://red-horde.net", "description": "freely blissfully ultimate huzzah instead along sometimes whale asset", "is_member": false, "job_url": "https://every-horde.com", "member_type": ""} "404": application/json: {"message": ""} + "400": + application/json: {"message": ""} get_event: speakeasy-default-get-event: parameters: @@ -1330,6 +1355,8 @@ examples: application/json: {"key": "", "name": "", "start_date": "2025-03-27T08:42:01.834Z"} "404": application/json: {"message": ""} + "400": + application/json: {"message": ""} get_issue: speakeasy-default-get-issue: parameters: @@ -1342,6 +1369,8 @@ examples: application/json: {"created_at": "2023-01-06T05:13:46.833Z", "state": "closed", "title": "", "updated_at": "2025-07-15T09:16:08.428Z", "url": "https://unaware-intent.net/", "body": ""} "404": application/json: {"message": ""} + "400": + application/json: {"message": ""} get_release: speakeasy-default-get-release: parameters: @@ -1354,6 +1383,8 @@ examples: application/json: {"created_at": "2023-02-28T19:12:54.485Z", "name": "", "tag_name": "", "description": "zowie beside endow ah"} "404": application/json: {"message": ""} + "400": + application/json: {"message": ""} get_repository: speakeasy-default-get-repository: parameters: @@ -1365,6 +1396,8 @@ examples: application/json: {"created_at": "2023-06-15T20:38:08.250Z", "name": "", "updated_at": "2024-06-04T00:23:47.329Z", "commits_count": 151332, "contributors_count": 474468, "forks_count": 777327, "open_issues_count": 454143, "stars_count": 733383} "404": application/json: {"message": ""} + "400": + application/json: {"message": ""} list_milestones: speakeasy-default-list-milestones: parameters: @@ -1388,6 +1421,8 @@ examples: application/json: {"created_at": "2023-09-01T23:58:56.084Z", "number": 88227, "state": "open", "title": "", "updated_at": "2023-09-20T07:01:10.505Z", "url": "https://impressive-configuration.name/", "body": "", "closed_issues_count": 545798, "due_on": "2024-01-25T11:51:50.047Z", "open_issues_count": 564718} "404": application/json: {"message": ""} + "400": + application/json: {"message": ""} list_snapshots: speakeasy-default-list-snapshots: parameters: @@ -1407,6 +1442,8 @@ examples: application/json: {"created_at": "2024-04-06T05:40:07.635Z", "end_at": "2025-03-11T07:21:35.938Z", "key": "", "start_at": "2025-08-24T22:14:42.145Z", "title": "", "updated_at": "2025-02-23T14:51:34.958Z", "new_chapters_count": 496225, "new_issues_count": 881483, "new_projects_count": 374148, "new_releases_count": 709291, "new_users_count": 456156} "404": application/json: {"message": ""} + "400": + application/json: {"message": ""} list_snapshot_chapters: speakeasy-default-list-snapshot-chapters: parameters: @@ -1463,10 +1500,7 @@ examples: "200": application/json: {"current_page": 719171, "has_next": true, "has_previous": false, "items": [], "total_count": 715591, "total_pages": 776129} examplesVersion: 1.0.2 -releaseNotes: | - ## Python SDK Changes: - * `nest.chapters.get_chapter()`: `response.leaders` **Added** - * `nest.projects.get_project()`: `response.leaders` **Added** +releaseNotes: "## Python SDK Changes:\n* `nest.events.list_events()`: `response.items[]` **Changed** (Breaking ⚠️)\n* `nest.events.get_event()`: \n * `response` **Changed** (Breaking ⚠️)\n * `error.status[400]` **Added**\n* `nest.community.get_organization()`: `error.status[400]` **Added**\n* `nest.committees.get_committee()`: `error.status[400]` **Added**\n* `nest.issues.get_issue()`: `error.status[400]` **Added**\n* `nest.community.get_member()`: `error.status[400]` **Added**\n* `nest.chapters.get_chapter()`: `error.status[400]` **Added**\n* `nest.community.get_snapshot()`: `error.status[400]` **Added**\n* `nest.milestones.get_milestone()`: `error.status[400]` **Added**\n* `nest.projects.list_projects()`: `request.q` **Added**\n* `nest.projects.get_project()`: `error.status[400]` **Added**\n* `nest.releases.get_release()`: `error.status[400]` **Added**\n* `nest.repositories.get_repository()`: `error.status[400]` **Added**\n* `nest.sponsors.get_sponsor()`: `error.status[400]` **Added**\n" generatedFiles: - .gitattributes - .vscode/settings.json diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index 179d348..7497840 100644 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -13,6 +13,7 @@ generation: requestResponseComponentNamesFeb2024: true securityFeb2025: true sharedErrorComponentsApr2025: true + sharedNestedComponentsJan2026: false auth: oAuth2ClientCredentialsEnabled: false oAuth2PasswordEnabled: false @@ -21,6 +22,7 @@ generation: schemas: allOfMergeStrategy: shallowMerge requestBodyFieldName: "" + versioningStrategy: automatic persistentEdits: {} tests: generateTests: false @@ -30,7 +32,7 @@ generation: backoffStrategy: exponential maxRetries: 3 python: - version: 0.3.7 + version: 0.4.0 additionalDependencies: dev: {} main: {} @@ -77,3 +79,4 @@ python: responseFormat: flat sseFlatResponse: false templateVersion: v2 + useAsyncHooks: false diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index 8884e37..a3b33cc 100644 --- a/.speakeasy/workflow.lock +++ b/.speakeasy/workflow.lock @@ -1,12 +1,12 @@ -speakeasyVersion: 1.680.12 +speakeasyVersion: 1.706.1 sources: nest-openapi: sourceNamespace: python-sdk - sourceRevisionDigest: sha256:1ec8b5202117c9fab033b9e860db0c29e3a3bc583b8d16f38d0600f994596686 - sourceBlobDigest: sha256:143881682a7f254e0910541f26427e13242d4cf68f6c5a09e4b07742eaac668f + sourceRevisionDigest: sha256:ac60db7c34c5d7d0165c8b04d171166325eae3f0c93ef5e02471550a2fe70aa6 + sourceBlobDigest: sha256:9a16c6178e04db6291b58f83fac8ec5dcce22793c8862125c67b83bb60bbd576 tags: - latest - - speakeasy-sdk-regen-1767573730 + - speakeasy-sdk-regen-1769388120 - 0.3.6 targets: nest-api: @@ -19,10 +19,10 @@ targets: nest-sdk-python: source: nest-openapi sourceNamespace: python-sdk - sourceRevisionDigest: sha256:1ec8b5202117c9fab033b9e860db0c29e3a3bc583b8d16f38d0600f994596686 - sourceBlobDigest: sha256:143881682a7f254e0910541f26427e13242d4cf68f6c5a09e4b07742eaac668f + sourceRevisionDigest: sha256:ac60db7c34c5d7d0165c8b04d171166325eae3f0c93ef5e02471550a2fe70aa6 + sourceBlobDigest: sha256:9a16c6178e04db6291b58f83fac8ec5dcce22793c8862125c67b83bb60bbd576 codeSamplesNamespace: python-code-samples - codeSamplesRevisionDigest: sha256:7fd55e0ebc1e8b2270743b5aa79d8ebee70911bb284f477ee405403ca4650add + codeSamplesRevisionDigest: sha256:4ca09ab3e3248399bfa86972282727a9f10e9c9804697ed51215142ba34414c8 workflow: workflowVersion: 1.0.0 speakeasyVersion: latest diff --git a/README-PYPI.md b/README-PYPI.md index a44f168..e565591 100644 --- a/README-PYPI.md +++ b/README-PYPI.md @@ -83,7 +83,7 @@ It's also possible to write a standalone Python script without needing to set up ```python #!/usr/bin/env -S uv run --script # /// script -# requires-python = ">=3.9" +# requires-python = ">=3.10" # dependencies = [ # "owasp-nest", # ] @@ -310,6 +310,7 @@ with Nest( ### Example ```python +import owasp_nest from owasp_nest import Nest, models @@ -334,15 +335,16 @@ with Nest( print(e.raw_response) # Depending on the method different errors may be thrown - if isinstance(e, models.ChapterError): + if isinstance(e, models.ValidationErrorSchema): print(e.data.message) # str + print(e.data.errors) # OptionalNullable[owasp_nest.Errors] ``` ### Error Classes **Primary error:** * [`NestError`](https://github.com/OWASP/nest-sdk-python/blob/master/./src/owasp_nest/models/nesterror.py): The base class for HTTP error responses. -
Less common errors (17) +
Less common errors (18)
@@ -353,6 +355,7 @@ with Nest( **Inherit from [`NestError`](https://github.com/OWASP/nest-sdk-python/blob/master/./src/owasp_nest/models/nesterror.py)**: +* [`ValidationErrorSchema`](https://github.com/OWASP/nest-sdk-python/blob/master/./src/owasp_nest/models/validationerrorschema.py): Schema for validation error. Status code `400`. Applicable to 12 of 29 methods.* * [`ChapterError`](https://github.com/OWASP/nest-sdk-python/blob/master/./src/owasp_nest/models/chaptererror.py): Chapter error schema. Status code `404`. Applicable to 1 of 29 methods.* * [`CommitteeError`](https://github.com/OWASP/nest-sdk-python/blob/master/./src/owasp_nest/models/committeeerror.py): Committee error schema. Status code `404`. Applicable to 1 of 29 methods.* * [`EventError`](https://github.com/OWASP/nest-sdk-python/blob/master/./src/owasp_nest/models/eventerror.py): Event error schema. Status code `404`. Applicable to 1 of 29 methods.* diff --git a/README.md b/README.md index b480b2f..f395287 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ It's also possible to write a standalone Python script without needing to set up ```python #!/usr/bin/env -S uv run --script # /// script -# requires-python = ">=3.9" +# requires-python = ">=3.10" # dependencies = [ # "owasp-nest", # ] @@ -310,6 +310,7 @@ with Nest( ### Example ```python +import owasp_nest from owasp_nest import Nest, models @@ -334,15 +335,16 @@ with Nest( print(e.raw_response) # Depending on the method different errors may be thrown - if isinstance(e, models.ChapterError): + if isinstance(e, models.ValidationErrorSchema): print(e.data.message) # str + print(e.data.errors) # OptionalNullable[owasp_nest.Errors] ``` ### Error Classes **Primary error:** * [`NestError`](./src/owasp_nest/models/nesterror.py): The base class for HTTP error responses. -
Less common errors (17) +
Less common errors (18)
@@ -353,6 +355,7 @@ with Nest( **Inherit from [`NestError`](./src/owasp_nest/models/nesterror.py)**: +* [`ValidationErrorSchema`](./src/owasp_nest/models/validationerrorschema.py): Schema for validation error. Status code `400`. Applicable to 12 of 29 methods.* * [`ChapterError`](./src/owasp_nest/models/chaptererror.py): Chapter error schema. Status code `404`. Applicable to 1 of 29 methods.* * [`CommitteeError`](./src/owasp_nest/models/committeeerror.py): Committee error schema. Status code `404`. Applicable to 1 of 29 methods.* * [`EventError`](./src/owasp_nest/models/eventerror.py): Event error schema. Status code `404`. Applicable to 1 of 29 methods.* diff --git a/RELEASES.md b/RELEASES.md index 0bdb2aa..7c048b6 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -146,4 +146,14 @@ Based on: ### Generated - [python v0.3.7] . ### Releases -- [PyPI v0.3.7] https://pypi.org/project/owasp-nest/0.3.7 - . \ No newline at end of file +- [PyPI v0.3.7] https://pypi.org/project/owasp-nest/0.3.7 - . + +## 2026-02-06 00:43:25 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.706.1 (2.809.2) https://github.com/speakeasy-api/speakeasy +### Generated +- [python v0.4.0] . +### Releases +- [PyPI v0.4.0] https://pypi.org/project/owasp-nest/0.4.0 - . \ No newline at end of file diff --git a/docs/models/errors.md b/docs/models/errors.md new file mode 100644 index 0000000..fc1e63c --- /dev/null +++ b/docs/models/errors.md @@ -0,0 +1,17 @@ +# Errors + + +## Supported Types + +### `List[Dict[str, Any]]` + +```python +value: List[Dict[str, Any]] = /* values here */ +``` + +### `Dict[str, Any]` + +```python +value: Dict[str, Any] = /* values here */ +``` + diff --git a/docs/models/event.md b/docs/models/event.md index bdcc811..75d4000 100644 --- a/docs/models/event.md +++ b/docs/models/event.md @@ -5,12 +5,12 @@ Schema for Event (minimal fields for list display). ## Fields -| Field | Type | Required | Description | -| -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `end_date` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_minus_sign: | N/A | -| `key` | *str* | :heavy_check_mark: | N/A | -| `latitude` | *OptionalNullable[float]* | :heavy_minus_sign: | N/A | -| `longitude` | *OptionalNullable[float]* | :heavy_minus_sign: | N/A | -| `name` | *str* | :heavy_check_mark: | N/A | -| `start_date` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_check_mark: | N/A | -| `url` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | \ No newline at end of file +| Field | Type | Required | Description | +| ------------------------- | ------------------------- | ------------------------- | ------------------------- | +| `end_date` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | +| `key` | *str* | :heavy_check_mark: | N/A | +| `latitude` | *OptionalNullable[float]* | :heavy_minus_sign: | N/A | +| `longitude` | *OptionalNullable[float]* | :heavy_minus_sign: | N/A | +| `name` | *str* | :heavy_check_mark: | N/A | +| `start_date` | *str* | :heavy_check_mark: | N/A | +| `url` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | \ No newline at end of file diff --git a/docs/models/eventdetail.md b/docs/models/eventdetail.md index e31b052..40f502a 100644 --- a/docs/models/eventdetail.md +++ b/docs/models/eventdetail.md @@ -5,13 +5,13 @@ Detail schema for Event (used in single item endpoints). ## Fields -| Field | Type | Required | Description | -| -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `end_date` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_minus_sign: | N/A | -| `key` | *str* | :heavy_check_mark: | N/A | -| `latitude` | *OptionalNullable[float]* | :heavy_minus_sign: | N/A | -| `longitude` | *OptionalNullable[float]* | :heavy_minus_sign: | N/A | -| `name` | *str* | :heavy_check_mark: | N/A | -| `start_date` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_check_mark: | N/A | -| `url` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | -| `description` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | \ No newline at end of file +| Field | Type | Required | Description | +| ------------------------- | ------------------------- | ------------------------- | ------------------------- | +| `end_date` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | +| `key` | *str* | :heavy_check_mark: | N/A | +| `latitude` | *OptionalNullable[float]* | :heavy_minus_sign: | N/A | +| `longitude` | *OptionalNullable[float]* | :heavy_minus_sign: | N/A | +| `name` | *str* | :heavy_check_mark: | N/A | +| `start_date` | *str* | :heavy_check_mark: | N/A | +| `url` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | +| `description` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | \ No newline at end of file diff --git a/docs/models/listprojectsrequest.md b/docs/models/listprojectsrequest.md index c0bcfce..bfc0830 100644 --- a/docs/models/listprojectsrequest.md +++ b/docs/models/listprojectsrequest.md @@ -6,6 +6,7 @@ | Field | Type | Required | Description | | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | | `level` | [OptionalNullable[models.ProjectLevel]](../models/projectlevel.md) | :heavy_minus_sign: | Level of the project | +| `q` | *OptionalNullable[str]* | :heavy_minus_sign: | Structured search query (e.g. 'name:security stars:>100') | | `ordering` | [OptionalNullable[models.ListProjectsOrdering]](../models/listprojectsordering.md) | :heavy_minus_sign: | Ordering field | | `page` | *Optional[int]* | :heavy_minus_sign: | Page number | | `page_size` | *Optional[int]* | :heavy_minus_sign: | Number of items per page | \ No newline at end of file diff --git a/docs/models/validationerrorschema.md b/docs/models/validationerrorschema.md new file mode 100644 index 0000000..3ad353d --- /dev/null +++ b/docs/models/validationerrorschema.md @@ -0,0 +1,11 @@ +# ValidationErrorSchema + +Schema for validation error. + + +## Fields + +| Field | Type | Required | Description | +| ------------------------------------------------------ | ------------------------------------------------------ | ------------------------------------------------------ | ------------------------------------------------------ | +| `message` | *str* | :heavy_check_mark: | N/A | +| `errors` | [OptionalNullable[models.Errors]](../models/errors.md) | :heavy_minus_sign: | N/A | \ No newline at end of file diff --git a/docs/sdks/chapters/README.md b/docs/sdks/chapters/README.md index 75f0ff1..ab778c6 100644 --- a/docs/sdks/chapters/README.md +++ b/docs/sdks/chapters/README.md @@ -88,7 +88,8 @@ with Nest( ### Errors -| Error Type | Status Code | Content Type | -| ------------------- | ------------------- | ------------------- | -| models.ChapterError | 404 | application/json | -| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file +| Error Type | Status Code | Content Type | +| ---------------------------- | ---------------------------- | ---------------------------- | +| models.ValidationErrorSchema | 400 | application/json | +| models.ChapterError | 404 | application/json | +| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/docs/sdks/committees/README.md b/docs/sdks/committees/README.md index 86e7763..03c6a98 100644 --- a/docs/sdks/committees/README.md +++ b/docs/sdks/committees/README.md @@ -83,7 +83,8 @@ with Nest( ### Errors -| Error Type | Status Code | Content Type | -| --------------------- | --------------------- | --------------------- | -| models.CommitteeError | 404 | application/json | -| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file +| Error Type | Status Code | Content Type | +| ---------------------------- | ---------------------------- | ---------------------------- | +| models.ValidationErrorSchema | 400 | application/json | +| models.CommitteeError | 404 | application/json | +| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/docs/sdks/community/README.md b/docs/sdks/community/README.md index 83e475a..a293e07 100644 --- a/docs/sdks/community/README.md +++ b/docs/sdks/community/README.md @@ -94,10 +94,11 @@ with Nest( ### Errors -| Error Type | Status Code | Content Type | -| ------------------- | ------------------- | ------------------- | -| models.MemberError | 404 | application/json | -| models.NestAPIError | 4XX, 5XX | \*/\* | +| Error Type | Status Code | Content Type | +| ---------------------------- | ---------------------------- | ---------------------------- | +| models.ValidationErrorSchema | 400 | application/json | +| models.MemberError | 404 | application/json | +| models.NestAPIError | 4XX, 5XX | \*/\* | ## list_organizations @@ -176,10 +177,11 @@ with Nest( ### Errors -| Error Type | Status Code | Content Type | -| ------------------------ | ------------------------ | ------------------------ | -| models.OrganizationError | 404 | application/json | -| models.NestAPIError | 4XX, 5XX | \*/\* | +| Error Type | Status Code | Content Type | +| ---------------------------- | ---------------------------- | ---------------------------- | +| models.ValidationErrorSchema | 400 | application/json | +| models.OrganizationError | 404 | application/json | +| models.NestAPIError | 4XX, 5XX | \*/\* | ## list_snapshots @@ -257,10 +259,11 @@ with Nest( ### Errors -| Error Type | Status Code | Content Type | -| -------------------- | -------------------- | -------------------- | -| models.SnapshotError | 404 | application/json | -| models.NestAPIError | 4XX, 5XX | \*/\* | +| Error Type | Status Code | Content Type | +| ---------------------------- | ---------------------------- | ---------------------------- | +| models.ValidationErrorSchema | 400 | application/json | +| models.SnapshotError | 404 | application/json | +| models.NestAPIError | 4XX, 5XX | \*/\* | ## list_snapshot_chapters diff --git a/docs/sdks/events/README.md b/docs/sdks/events/README.md index 40d919b..6abab19 100644 --- a/docs/sdks/events/README.md +++ b/docs/sdks/events/README.md @@ -88,7 +88,8 @@ with Nest( ### Errors -| Error Type | Status Code | Content Type | -| ------------------- | ------------------- | ------------------- | -| models.EventError | 404 | application/json | -| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file +| Error Type | Status Code | Content Type | +| ---------------------------- | ---------------------------- | ---------------------------- | +| models.ValidationErrorSchema | 400 | application/json | +| models.EventError | 404 | application/json | +| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/docs/sdks/issues/README.md b/docs/sdks/issues/README.md index 6bed211..7a27723 100644 --- a/docs/sdks/issues/README.md +++ b/docs/sdks/issues/README.md @@ -88,7 +88,8 @@ with Nest( ### Errors -| Error Type | Status Code | Content Type | -| ------------------- | ------------------- | ------------------- | -| models.IssueError | 404 | application/json | -| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file +| Error Type | Status Code | Content Type | +| ---------------------------- | ---------------------------- | ---------------------------- | +| models.ValidationErrorSchema | 400 | application/json | +| models.IssueError | 404 | application/json | +| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/docs/sdks/milestones/README.md b/docs/sdks/milestones/README.md index d1ca109..79eb897 100644 --- a/docs/sdks/milestones/README.md +++ b/docs/sdks/milestones/README.md @@ -88,7 +88,8 @@ with Nest( ### Errors -| Error Type | Status Code | Content Type | -| --------------------- | --------------------- | --------------------- | -| models.MilestoneError | 404 | application/json | -| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file +| Error Type | Status Code | Content Type | +| ---------------------------- | ---------------------------- | ---------------------------- | +| models.ValidationErrorSchema | 400 | application/json | +| models.MilestoneError | 404 | application/json | +| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/docs/sdks/projects/README.md b/docs/sdks/projects/README.md index be9aa1d..892ad31 100644 --- a/docs/sdks/projects/README.md +++ b/docs/sdks/projects/README.md @@ -35,6 +35,7 @@ with Nest( | Parameter | Type | Required | Description | | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | `level` | [OptionalNullable[models.ProjectLevel]](../../models/projectlevel.md) | :heavy_minus_sign: | Level of the project | +| `q` | *OptionalNullable[str]* | :heavy_minus_sign: | Structured search query (e.g. 'name:security stars:>100') | | `ordering` | [OptionalNullable[models.ListProjectsOrdering]](../../models/listprojectsordering.md) | :heavy_minus_sign: | Ordering field | | `page` | *Optional[int]* | :heavy_minus_sign: | Page number | | `page_size` | *Optional[int]* | :heavy_minus_sign: | Number of items per page | @@ -85,7 +86,8 @@ with Nest( ### Errors -| Error Type | Status Code | Content Type | -| ------------------- | ------------------- | ------------------- | -| models.ProjectError | 404 | application/json | -| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file +| Error Type | Status Code | Content Type | +| ---------------------------- | ---------------------------- | ---------------------------- | +| models.ValidationErrorSchema | 400 | application/json | +| models.ProjectError | 404 | application/json | +| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/docs/sdks/releases/README.md b/docs/sdks/releases/README.md index 6776572..e5995cc 100644 --- a/docs/sdks/releases/README.md +++ b/docs/sdks/releases/README.md @@ -88,7 +88,8 @@ with Nest( ### Errors -| Error Type | Status Code | Content Type | -| ------------------- | ------------------- | ------------------- | -| models.ReleaseError | 404 | application/json | -| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file +| Error Type | Status Code | Content Type | +| ---------------------------- | ---------------------------- | ---------------------------- | +| models.ValidationErrorSchema | 400 | application/json | +| models.ReleaseError | 404 | application/json | +| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/docs/sdks/repositories/README.md b/docs/sdks/repositories/README.md index d18def6..d3cdb2d 100644 --- a/docs/sdks/repositories/README.md +++ b/docs/sdks/repositories/README.md @@ -85,7 +85,8 @@ with Nest( ### Errors -| Error Type | Status Code | Content Type | -| ---------------------- | ---------------------- | ---------------------- | -| models.RepositoryError | 404 | application/json | -| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file +| Error Type | Status Code | Content Type | +| ---------------------------- | ---------------------------- | ---------------------------- | +| models.ValidationErrorSchema | 400 | application/json | +| models.RepositoryError | 404 | application/json | +| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/docs/sdks/sponsors/README.md b/docs/sdks/sponsors/README.md index a3c0bfc..334976d 100644 --- a/docs/sdks/sponsors/README.md +++ b/docs/sdks/sponsors/README.md @@ -86,7 +86,8 @@ with Nest( ### Errors -| Error Type | Status Code | Content Type | -| ------------------- | ------------------- | ------------------- | -| models.SponsorError | 404 | application/json | -| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file +| Error Type | Status Code | Content Type | +| ---------------------------- | ---------------------------- | ---------------------------- | +| models.ValidationErrorSchema | 400 | application/json | +| models.SponsorError | 404 | application/json | +| models.NestAPIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/pylintrc b/pylintrc index 7f1dd32..2dc74cb 100644 --- a/pylintrc +++ b/pylintrc @@ -89,7 +89,7 @@ persistent=yes # Minimum Python version to use for version dependent checks. Will default to # the version used to run pylint. -py-version=3.9 +py-version=3.10 # Discover python modules and packages in the file system subtree. recursive=no @@ -187,7 +187,8 @@ good-names=i, ex, Run, _, - e + e, + q # Good variable names regexes, separated by a comma. If names match any regex, # they will always be accepted diff --git a/pyproject.toml b/pyproject.toml index 448a509..08d2eab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,10 @@ [project] name = "owasp-nest" -version = "0.3.7" +version = "0.4.0" description = "OWASP Nest Python SDK" authors = [{ name = "Arkadii Yakovets" },] readme = "README-PYPI.md" -requires-python = ">=3.9.2" +requires-python = ">=3.10" dependencies = [ "httpcore >=1.0.9", "httpx >=0.28.1", diff --git a/src/owasp_nest/_version.py b/src/owasp_nest/_version.py index 0052f63..eb92b10 100644 --- a/src/owasp_nest/_version.py +++ b/src/owasp_nest/_version.py @@ -3,10 +3,10 @@ import importlib.metadata __title__: str = "owasp-nest" -__version__: str = "0.3.7" +__version__: str = "0.4.0" __openapi_doc_version__: str = "0.3.6" -__gen_version__: str = "2.788.15" -__user_agent__: str = "speakeasy-sdk/python 0.3.7 2.788.15 0.3.6 owasp-nest" +__gen_version__: str = "2.809.2" +__user_agent__: str = "speakeasy-sdk/python 0.4.0 2.809.2 0.3.6 owasp-nest" try: if __package__ is not None: diff --git a/src/owasp_nest/basesdk.py b/src/owasp_nest/basesdk.py index 65969ec..7367bab 100644 --- a/src/owasp_nest/basesdk.py +++ b/src/owasp_nest/basesdk.py @@ -8,7 +8,12 @@ AfterSuccessContext, BeforeRequestContext, ) -from owasp_nest.utils import RetryConfig, SerializedRequestBody, get_body_content +from owasp_nest.utils import ( + RetryConfig, + SerializedRequestBody, + get_body_content, + run_sync_in_thread, +) from typing import Callable, List, Mapping, Optional, Tuple from urllib.parse import parse_qs, urlparse @@ -311,7 +316,10 @@ async def do_request_async( async def do(): http_res = None try: - req = hooks.before_request(BeforeRequestContext(hook_ctx), request) + req = await run_sync_in_thread( + hooks.before_request, BeforeRequestContext(hook_ctx), request + ) + logger.debug( "Request:\nMethod: %s\nURL: %s\nHeaders: %s\nBody: %s", req.method, @@ -325,7 +333,10 @@ async def do(): http_res = await client.send(req, stream=stream) except Exception as e: - _, e = hooks.after_error(AfterErrorContext(hook_ctx), None, e) + _, e = await run_sync_in_thread( + hooks.after_error, AfterErrorContext(hook_ctx), None, e + ) + if e is not None: logger.debug("Request Exception", exc_info=True) raise e @@ -343,9 +354,10 @@ async def do(): ) if utils.match_status_codes(error_status_codes, http_res.status_code): - result, err = hooks.after_error( - AfterErrorContext(hook_ctx), http_res, None + result, err = await run_sync_in_thread( + hooks.after_error, AfterErrorContext(hook_ctx), http_res, None ) + if err is not None: logger.debug("Request Exception", exc_info=True) raise err @@ -365,6 +377,8 @@ async def do(): http_res = await do() if not utils.match_status_codes(error_status_codes, http_res.status_code): - http_res = hooks.after_success(AfterSuccessContext(hook_ctx), http_res) + http_res = await run_sync_in_thread( + hooks.after_success, AfterSuccessContext(hook_ctx), http_res + ) return http_res diff --git a/src/owasp_nest/chapters.py b/src/owasp_nest/chapters.py index f89cdae..1cd1216 100644 --- a/src/owasp_nest/chapters.py +++ b/src/owasp_nest/chapters.py @@ -282,13 +282,18 @@ def get_chapter( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.ChapterDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.ChapterErrorData, http_res) raise models.ChapterError(response_data, http_res) @@ -368,13 +373,18 @@ async def get_chapter_async( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.ChapterDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.ChapterErrorData, http_res) raise models.ChapterError(response_data, http_res) diff --git a/src/owasp_nest/committees.py b/src/owasp_nest/committees.py index 341b5f6..c878502 100644 --- a/src/owasp_nest/committees.py +++ b/src/owasp_nest/committees.py @@ -252,13 +252,18 @@ def get_committee( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.CommitteeDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.CommitteeErrorData, http_res) raise models.CommitteeError(response_data, http_res) @@ -338,13 +343,18 @@ async def get_committee_async( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.CommitteeDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.CommitteeErrorData, http_res) raise models.CommitteeError(response_data, http_res) diff --git a/src/owasp_nest/community.py b/src/owasp_nest/community.py index 459b5b7..46c7407 100644 --- a/src/owasp_nest/community.py +++ b/src/owasp_nest/community.py @@ -264,13 +264,18 @@ def get_member( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.MemberDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.MemberErrorData, http_res) raise models.MemberError(response_data, http_res) @@ -350,13 +355,18 @@ async def get_member_async( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.MemberDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.MemberErrorData, http_res) raise models.MemberError(response_data, http_res) @@ -618,13 +628,18 @@ def get_organization( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.OrganizationDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response( models.OrganizationErrorData, http_res @@ -706,13 +721,18 @@ async def get_organization_async( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.OrganizationDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response( models.OrganizationErrorData, http_res @@ -970,13 +990,18 @@ def get_snapshot( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.SnapshotDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.SnapshotErrorData, http_res) raise models.SnapshotError(response_data, http_res) @@ -1056,13 +1081,18 @@ async def get_snapshot_async( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.SnapshotDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.SnapshotErrorData, http_res) raise models.SnapshotError(response_data, http_res) diff --git a/src/owasp_nest/events.py b/src/owasp_nest/events.py index b2081f2..0486371 100644 --- a/src/owasp_nest/events.py +++ b/src/owasp_nest/events.py @@ -282,13 +282,18 @@ def get_event( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.EventDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.EventErrorData, http_res) raise models.EventError(response_data, http_res) @@ -368,13 +373,18 @@ async def get_event_async( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.EventDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.EventErrorData, http_res) raise models.EventError(response_data, http_res) diff --git a/src/owasp_nest/issues.py b/src/owasp_nest/issues.py index f2ad9e1..c86e7a1 100644 --- a/src/owasp_nest/issues.py +++ b/src/owasp_nest/issues.py @@ -276,13 +276,18 @@ def get_issue( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.IssueDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.IssueErrorData, http_res) raise models.IssueError(response_data, http_res) @@ -368,13 +373,18 @@ async def get_issue_async( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.IssueDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.IssueErrorData, http_res) raise models.IssueError(response_data, http_res) diff --git a/src/owasp_nest/milestones.py b/src/owasp_nest/milestones.py index c448fad..c8d1725 100644 --- a/src/owasp_nest/milestones.py +++ b/src/owasp_nest/milestones.py @@ -276,13 +276,18 @@ def get_milestone( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.MilestoneDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.MilestoneErrorData, http_res) raise models.MilestoneError(response_data, http_res) @@ -368,13 +373,18 @@ async def get_milestone_async( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.MilestoneDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.MilestoneErrorData, http_res) raise models.MilestoneError(response_data, http_res) diff --git a/src/owasp_nest/models/__init__.py b/src/owasp_nest/models/__init__.py index a01eaf4..7884bb3 100644 --- a/src/owasp_nest/models/__init__.py +++ b/src/owasp_nest/models/__init__.py @@ -170,6 +170,12 @@ from .sponsordetail import SponsorDetail, SponsorDetailTypedDict from .sponsorerror import SponsorError, SponsorErrorData from .state import State + from .validationerrorschema import ( + Errors, + ErrorsTypedDict, + ValidationErrorSchema, + ValidationErrorSchemaData, + ) __all__ = [ "Chapter", @@ -184,6 +190,8 @@ "CommitteeError", "CommitteeErrorData", "CommitteeTypedDict", + "Errors", + "ErrorsTypedDict", "Event", "EventDetail", "EventDetailTypedDict", @@ -362,6 +370,8 @@ "SponsorErrorData", "SponsorTypedDict", "State", + "ValidationErrorSchema", + "ValidationErrorSchemaData", ] _dynamic_imports: dict[str, str] = { @@ -554,6 +564,10 @@ "SponsorError": ".sponsorerror", "SponsorErrorData": ".sponsorerror", "State": ".state", + "Errors": ".validationerrorschema", + "ErrorsTypedDict": ".validationerrorschema", + "ValidationErrorSchema": ".validationerrorschema", + "ValidationErrorSchemaData": ".validationerrorschema", } diff --git a/src/owasp_nest/models/chapter.py b/src/owasp_nest/models/chapter.py index ee2af8d..32eea35 100644 --- a/src/owasp_nest/models/chapter.py +++ b/src/owasp_nest/models/chapter.py @@ -41,30 +41,25 @@ class Chapter(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["latitude", "longitude"] - nullable_fields = ["latitude", "longitude"] - null_default_fields = [] - + optional_fields = set(["latitude", "longitude"]) + nullable_fields = set(["latitude", "longitude"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/chapterdetail.py b/src/owasp_nest/models/chapterdetail.py index 0f5773f..697013a 100644 --- a/src/owasp_nest/models/chapterdetail.py +++ b/src/owasp_nest/models/chapterdetail.py @@ -52,30 +52,25 @@ class ChapterDetail(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["latitude", "longitude"] - nullable_fields = ["latitude", "longitude"] - null_default_fields = [] - + optional_fields = set(["latitude", "longitude"]) + nullable_fields = set(["latitude", "longitude"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/event.py b/src/owasp_nest/models/event.py index 25a63af..dc0159a 100644 --- a/src/owasp_nest/models/event.py +++ b/src/owasp_nest/models/event.py @@ -1,7 +1,6 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" from __future__ import annotations -from datetime import datetime from owasp_nest.types import ( BaseModel, Nullable, @@ -18,8 +17,8 @@ class EventTypedDict(TypedDict): key: str name: str - start_date: datetime - end_date: NotRequired[Nullable[datetime]] + start_date: str + end_date: NotRequired[Nullable[str]] latitude: NotRequired[Nullable[float]] longitude: NotRequired[Nullable[float]] url: NotRequired[Nullable[str]] @@ -32,9 +31,9 @@ class Event(BaseModel): name: str - start_date: datetime + start_date: str - end_date: OptionalNullable[datetime] = UNSET + end_date: OptionalNullable[str] = UNSET latitude: OptionalNullable[float] = UNSET @@ -44,30 +43,25 @@ class Event(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["end_date", "latitude", "longitude", "url"] - nullable_fields = ["end_date", "latitude", "longitude", "url"] - null_default_fields = [] - + optional_fields = set(["end_date", "latitude", "longitude", "url"]) + nullable_fields = set(["end_date", "latitude", "longitude", "url"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/eventdetail.py b/src/owasp_nest/models/eventdetail.py index 9f4f140..a7cd90d 100644 --- a/src/owasp_nest/models/eventdetail.py +++ b/src/owasp_nest/models/eventdetail.py @@ -1,7 +1,6 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" from __future__ import annotations -from datetime import datetime from owasp_nest.types import ( BaseModel, Nullable, @@ -18,8 +17,8 @@ class EventDetailTypedDict(TypedDict): key: str name: str - start_date: datetime - end_date: NotRequired[Nullable[datetime]] + start_date: str + end_date: NotRequired[Nullable[str]] latitude: NotRequired[Nullable[float]] longitude: NotRequired[Nullable[float]] url: NotRequired[Nullable[str]] @@ -33,9 +32,9 @@ class EventDetail(BaseModel): name: str - start_date: datetime + start_date: str - end_date: OptionalNullable[datetime] = UNSET + end_date: OptionalNullable[str] = UNSET latitude: OptionalNullable[float] = UNSET @@ -47,30 +46,29 @@ class EventDetail(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["end_date", "latitude", "longitude", "url", "description"] - nullable_fields = ["end_date", "latitude", "longitude", "url", "description"] - null_default_fields = [] - + optional_fields = set( + ["end_date", "latitude", "longitude", "url", "description"] + ) + nullable_fields = set( + ["end_date", "latitude", "longitude", "url", "description"] + ) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/leader.py b/src/owasp_nest/models/leader.py index a323917..cf80675 100644 --- a/src/owasp_nest/models/leader.py +++ b/src/owasp_nest/models/leader.py @@ -28,30 +28,25 @@ class Leader(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["key"] - nullable_fields = ["key"] - null_default_fields = [] - + optional_fields = set(["key"]) + nullable_fields = set(["key"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_chaptersop.py b/src/owasp_nest/models/list_chaptersop.py index b78e558..2dbee21 100644 --- a/src/owasp_nest/models/list_chaptersop.py +++ b/src/owasp_nest/models/list_chaptersop.py @@ -98,46 +98,45 @@ class ListChaptersRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = [ - "latitude_gte", - "latitude_lte", - "longitude_gte", - "longitude_lte", - "country", - "ordering", - "page", - "page_size", - ] - nullable_fields = [ - "latitude_gte", - "latitude_lte", - "longitude_gte", - "longitude_lte", - "country", - "ordering", - ] - null_default_fields = [] - + optional_fields = set( + [ + "latitude_gte", + "latitude_lte", + "longitude_gte", + "longitude_lte", + "country", + "ordering", + "page", + "page_size", + ] + ) + nullable_fields = set( + [ + "latitude_gte", + "latitude_lte", + "longitude_gte", + "longitude_lte", + "country", + "ordering", + ] + ) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_committeesop.py b/src/owasp_nest/models/list_committeesop.py index c65153b..82b1473 100644 --- a/src/owasp_nest/models/list_committeesop.py +++ b/src/owasp_nest/models/list_committeesop.py @@ -54,30 +54,25 @@ class ListCommitteesRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["ordering", "page", "page_size"] - nullable_fields = ["ordering"] - null_default_fields = [] - + optional_fields = set(["ordering", "page", "page_size"]) + nullable_fields = set(["ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_eventsop.py b/src/owasp_nest/models/list_eventsop.py index 042bf64..182e604 100644 --- a/src/owasp_nest/models/list_eventsop.py +++ b/src/owasp_nest/models/list_eventsop.py @@ -98,46 +98,45 @@ class ListEventsRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = [ - "latitude_gte", - "latitude_lte", - "longitude_gte", - "longitude_lte", - "ordering", - "is_upcoming", - "page", - "page_size", - ] - nullable_fields = [ - "latitude_gte", - "latitude_lte", - "longitude_gte", - "longitude_lte", - "ordering", - "is_upcoming", - ] - null_default_fields = [] - + optional_fields = set( + [ + "latitude_gte", + "latitude_lte", + "longitude_gte", + "longitude_lte", + "ordering", + "is_upcoming", + "page", + "page_size", + ] + ) + nullable_fields = set( + [ + "latitude_gte", + "latitude_lte", + "longitude_gte", + "longitude_lte", + "ordering", + "is_upcoming", + ] + ) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_issuesop.py b/src/owasp_nest/models/list_issuesop.py index 7e7e19f..e1e0cc9 100644 --- a/src/owasp_nest/models/list_issuesop.py +++ b/src/owasp_nest/models/list_issuesop.py @@ -79,37 +79,27 @@ class ListIssuesRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = [ - "organization", - "repository", - "state", - "ordering", - "page", - "page_size", - ] - nullable_fields = ["organization", "repository", "state", "ordering"] - null_default_fields = [] - + optional_fields = set( + ["organization", "repository", "state", "ordering", "page", "page_size"] + ) + nullable_fields = set(["organization", "repository", "state", "ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_membersop.py b/src/owasp_nest/models/list_membersop.py index e73cfe6..989e39a 100644 --- a/src/owasp_nest/models/list_membersop.py +++ b/src/owasp_nest/models/list_membersop.py @@ -70,30 +70,25 @@ class ListMembersRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["company", "location", "ordering", "page", "page_size"] - nullable_fields = ["company", "location", "ordering"] - null_default_fields = [] - + optional_fields = set(["company", "location", "ordering", "page", "page_size"]) + nullable_fields = set(["company", "location", "ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_milestonesop.py b/src/owasp_nest/models/list_milestonesop.py index 47d1c96..9222723 100644 --- a/src/owasp_nest/models/list_milestonesop.py +++ b/src/owasp_nest/models/list_milestonesop.py @@ -75,37 +75,27 @@ class ListMilestonesRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = [ - "organization", - "repository", - "state", - "ordering", - "page", - "page_size", - ] - nullable_fields = ["organization", "repository", "state", "ordering"] - null_default_fields = [] - + optional_fields = set( + ["organization", "repository", "state", "ordering", "page", "page_size"] + ) + nullable_fields = set(["organization", "repository", "state", "ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_organizationsop.py b/src/owasp_nest/models/list_organizationsop.py index e5da7ad..417e0dc 100644 --- a/src/owasp_nest/models/list_organizationsop.py +++ b/src/owasp_nest/models/list_organizationsop.py @@ -62,30 +62,25 @@ class ListOrganizationsRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["location", "ordering", "page", "page_size"] - nullable_fields = ["location", "ordering"] - null_default_fields = [] - + optional_fields = set(["location", "ordering", "page", "page_size"]) + nullable_fields = set(["location", "ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_projectsop.py b/src/owasp_nest/models/list_projectsop.py index 12233f0..2fb7621 100644 --- a/src/owasp_nest/models/list_projectsop.py +++ b/src/owasp_nest/models/list_projectsop.py @@ -28,6 +28,8 @@ class ListProjectsOrdering(str, Enum): class ListProjectsRequestTypedDict(TypedDict): level: NotRequired[Nullable[ProjectLevel]] r"""Level of the project""" + q: NotRequired[Nullable[str]] + r"""Structured search query (e.g. 'name:security stars:>100')""" ordering: NotRequired[Nullable[ListProjectsOrdering]] r"""Ordering field""" page: NotRequired[int] @@ -43,6 +45,12 @@ class ListProjectsRequest(BaseModel): ] = UNSET r"""Level of the project""" + q: Annotated[ + OptionalNullable[str], + FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), + ] = UNSET + r"""Structured search query (e.g. 'name:security stars:>100')""" + ordering: Annotated[ OptionalNullable[ListProjectsOrdering], FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), @@ -63,30 +71,25 @@ class ListProjectsRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["level", "ordering", "page", "page_size"] - nullable_fields = ["level", "ordering"] - null_default_fields = [] - + optional_fields = set(["level", "q", "ordering", "page", "page_size"]) + nullable_fields = set(["level", "q", "ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_releasesop.py b/src/owasp_nest/models/list_releasesop.py index 135973c..a55e884 100644 --- a/src/owasp_nest/models/list_releasesop.py +++ b/src/owasp_nest/models/list_releasesop.py @@ -78,37 +78,27 @@ class ListReleasesRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = [ - "organization", - "repository", - "tag_name", - "ordering", - "page", - "page_size", - ] - nullable_fields = ["organization", "repository", "tag_name", "ordering"] - null_default_fields = [] - + optional_fields = set( + ["organization", "repository", "tag_name", "ordering", "page", "page_size"] + ) + nullable_fields = set(["organization", "repository", "tag_name", "ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_repositoriesop.py b/src/owasp_nest/models/list_repositoriesop.py index 08e0687..1a1c5a7 100644 --- a/src/owasp_nest/models/list_repositoriesop.py +++ b/src/owasp_nest/models/list_repositoriesop.py @@ -62,30 +62,25 @@ class ListRepositoriesRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["organization_id", "ordering", "page", "page_size"] - nullable_fields = ["organization_id", "ordering"] - null_default_fields = [] - + optional_fields = set(["organization_id", "ordering", "page", "page_size"]) + nullable_fields = set(["organization_id", "ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_snapshot_chaptersop.py b/src/owasp_nest/models/list_snapshot_chaptersop.py index d54a824..76df097 100644 --- a/src/owasp_nest/models/list_snapshot_chaptersop.py +++ b/src/owasp_nest/models/list_snapshot_chaptersop.py @@ -59,30 +59,25 @@ class ListSnapshotChaptersRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["ordering", "page", "page_size"] - nullable_fields = ["ordering"] - null_default_fields = [] - + optional_fields = set(["ordering", "page", "page_size"]) + nullable_fields = set(["ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_snapshot_issuesop.py b/src/owasp_nest/models/list_snapshot_issuesop.py index 9d8f8c3..35052aa 100644 --- a/src/owasp_nest/models/list_snapshot_issuesop.py +++ b/src/owasp_nest/models/list_snapshot_issuesop.py @@ -59,30 +59,25 @@ class ListSnapshotIssuesRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["ordering", "page", "page_size"] - nullable_fields = ["ordering"] - null_default_fields = [] - + optional_fields = set(["ordering", "page", "page_size"]) + nullable_fields = set(["ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_snapshot_membersop.py b/src/owasp_nest/models/list_snapshot_membersop.py index 337497b..2a8583b 100644 --- a/src/owasp_nest/models/list_snapshot_membersop.py +++ b/src/owasp_nest/models/list_snapshot_membersop.py @@ -59,30 +59,25 @@ class ListSnapshotMembersRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["ordering", "page", "page_size"] - nullable_fields = ["ordering"] - null_default_fields = [] - + optional_fields = set(["ordering", "page", "page_size"]) + nullable_fields = set(["ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_snapshot_projectsop.py b/src/owasp_nest/models/list_snapshot_projectsop.py index 6849718..b63f5e7 100644 --- a/src/owasp_nest/models/list_snapshot_projectsop.py +++ b/src/owasp_nest/models/list_snapshot_projectsop.py @@ -59,30 +59,25 @@ class ListSnapshotProjectsRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["ordering", "page", "page_size"] - nullable_fields = ["ordering"] - null_default_fields = [] - + optional_fields = set(["ordering", "page", "page_size"]) + nullable_fields = set(["ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_snapshot_releasesop.py b/src/owasp_nest/models/list_snapshot_releasesop.py index 3d32d67..8f3314d 100644 --- a/src/owasp_nest/models/list_snapshot_releasesop.py +++ b/src/owasp_nest/models/list_snapshot_releasesop.py @@ -59,30 +59,25 @@ class ListSnapshotReleasesRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["ordering", "page", "page_size"] - nullable_fields = ["ordering"] - null_default_fields = [] - + optional_fields = set(["ordering", "page", "page_size"]) + nullable_fields = set(["ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_snapshotsop.py b/src/owasp_nest/models/list_snapshotsop.py index 270c932..99f2f41 100644 --- a/src/owasp_nest/models/list_snapshotsop.py +++ b/src/owasp_nest/models/list_snapshotsop.py @@ -56,30 +56,25 @@ class ListSnapshotsRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["ordering", "page", "page_size"] - nullable_fields = ["ordering"] - null_default_fields = [] - + optional_fields = set(["ordering", "page", "page_size"]) + nullable_fields = set(["ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/list_sponsorsop.py b/src/owasp_nest/models/list_sponsorsop.py index 5187dc7..3353fb0 100644 --- a/src/owasp_nest/models/list_sponsorsop.py +++ b/src/owasp_nest/models/list_sponsorsop.py @@ -77,37 +77,34 @@ class ListSponsorsRequest(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = [ - "is_member", - "member_type", - "sponsor_type", - "ordering", - "page", - "page_size", - ] - nullable_fields = ["is_member", "member_type", "sponsor_type", "ordering"] - null_default_fields = [] - + optional_fields = set( + [ + "is_member", + "member_type", + "sponsor_type", + "ordering", + "page", + "page_size", + ] + ) + nullable_fields = set(["is_member", "member_type", "sponsor_type", "ordering"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/milestonedetail.py b/src/owasp_nest/models/milestonedetail.py index 928283a..170f67e 100644 --- a/src/owasp_nest/models/milestonedetail.py +++ b/src/owasp_nest/models/milestonedetail.py @@ -48,30 +48,14 @@ class MilestoneDetail(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = [] - nullable_fields = ["due_on"] - null_default_fields = [] - serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): + if val != UNSET_SENTINEL: m[k] = val return m diff --git a/src/owasp_nest/models/release.py b/src/owasp_nest/models/release.py index fd82e37..0449dbf 100644 --- a/src/owasp_nest/models/release.py +++ b/src/owasp_nest/models/release.py @@ -35,30 +35,25 @@ class Release(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["published_at"] - nullable_fields = ["published_at"] - null_default_fields = [] - + optional_fields = set(["published_at"]) + nullable_fields = set(["published_at"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/releasedetail.py b/src/owasp_nest/models/releasedetail.py index 0c7ea93..f478c02 100644 --- a/src/owasp_nest/models/releasedetail.py +++ b/src/owasp_nest/models/releasedetail.py @@ -38,30 +38,25 @@ class ReleaseDetail(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["published_at"] - nullable_fields = ["published_at"] - null_default_fields = [] - + optional_fields = set(["published_at"]) + nullable_fields = set(["published_at"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/repositorydetail.py b/src/owasp_nest/models/repositorydetail.py index 1998ff0..88c814c 100644 --- a/src/owasp_nest/models/repositorydetail.py +++ b/src/owasp_nest/models/repositorydetail.py @@ -50,30 +50,25 @@ class RepositoryDetail(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["description"] - nullable_fields = ["description"] - null_default_fields = [] - + optional_fields = set(["description"]) + nullable_fields = set(["description"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/snapshotissue.py b/src/owasp_nest/models/snapshotissue.py index 3037f45..558e0d3 100644 --- a/src/owasp_nest/models/snapshotissue.py +++ b/src/owasp_nest/models/snapshotissue.py @@ -39,30 +39,14 @@ class SnapshotIssue(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = [] - nullable_fields = ["organization_login", "repository_name"] - null_default_fields = [] - serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): + if val != UNSET_SENTINEL: m[k] = val return m diff --git a/src/owasp_nest/models/snapshotrelease.py b/src/owasp_nest/models/snapshotrelease.py index 5af7ddc..12b5483 100644 --- a/src/owasp_nest/models/snapshotrelease.py +++ b/src/owasp_nest/models/snapshotrelease.py @@ -41,30 +41,25 @@ class SnapshotRelease(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = ["published_at"] - nullable_fields = ["published_at", "organization_login", "repository_name"] - null_default_fields = [] - + optional_fields = set(["published_at"]) + nullable_fields = set(["published_at", "organization_login", "repository_name"]) serialized = handler(self) - m = {} for n, f in type(self).model_fields.items(): k = f.alias or n val = serialized.get(k) - serialized.pop(k, None) - - optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member - - if val is not None and val != UNSET_SENTINEL: - m[k] = val - elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) - ): - m[k] = val + is_nullable_and_explicitly_set = ( + k in nullable_fields + and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member + ) + + if val != UNSET_SENTINEL: + if ( + val is not None + or k not in optional_fields + or is_nullable_and_explicitly_set + ): + m[k] = val return m diff --git a/src/owasp_nest/models/validationerrorschema.py b/src/owasp_nest/models/validationerrorschema.py new file mode 100644 index 0000000..ab9e722 --- /dev/null +++ b/src/owasp_nest/models/validationerrorschema.py @@ -0,0 +1,40 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from dataclasses import dataclass, field +import httpx +from owasp_nest.models import NestError +from owasp_nest.types import BaseModel, OptionalNullable, UNSET +from typing import Any, Dict, List, Optional, Union +from typing_extensions import TypeAliasType + + +ErrorsTypedDict = TypeAliasType( + "ErrorsTypedDict", Union[List[Dict[str, Any]], Dict[str, Any]] +) + + +Errors = TypeAliasType("Errors", Union[List[Dict[str, Any]], Dict[str, Any]]) + + +class ValidationErrorSchemaData(BaseModel): + message: str + errors: OptionalNullable[Errors] = UNSET + + +@dataclass(unsafe_hash=True) +class ValidationErrorSchema(NestError): + r"""Schema for validation error.""" + + data: ValidationErrorSchemaData = field(hash=False) + + def __init__( + self, + data: ValidationErrorSchemaData, + raw_response: httpx.Response, + body: Optional[str] = None, + ): + fallback = body or raw_response.text + message = str(data.message) or fallback + super().__init__(message, raw_response, body) + object.__setattr__(self, "data", data) diff --git a/src/owasp_nest/projects.py b/src/owasp_nest/projects.py index cf428b1..825ed28 100644 --- a/src/owasp_nest/projects.py +++ b/src/owasp_nest/projects.py @@ -13,6 +13,7 @@ def list_projects( self, *, level: OptionalNullable[models.ProjectLevel] = UNSET, + q: OptionalNullable[str] = UNSET, ordering: OptionalNullable[models.ListProjectsOrdering] = UNSET, page: Optional[int] = 1, page_size: Optional[int] = 100, @@ -26,6 +27,7 @@ def list_projects( Retrieve a paginated list of OWASP projects. :param level: Level of the project + :param q: Structured search query (e.g. 'name:security stars:>100') :param ordering: Ordering field :param page: Page number :param page_size: Number of items per page @@ -46,6 +48,7 @@ def list_projects( request = models.ListProjectsRequest( level=level, + q=q, ordering=ordering, page=page, page_size=page_size, @@ -104,6 +107,7 @@ async def list_projects_async( self, *, level: OptionalNullable[models.ProjectLevel] = UNSET, + q: OptionalNullable[str] = UNSET, ordering: OptionalNullable[models.ListProjectsOrdering] = UNSET, page: Optional[int] = 1, page_size: Optional[int] = 100, @@ -117,6 +121,7 @@ async def list_projects_async( Retrieve a paginated list of OWASP projects. :param level: Level of the project + :param q: Structured search query (e.g. 'name:security stars:>100') :param ordering: Ordering field :param page: Page number :param page_size: Number of items per page @@ -137,6 +142,7 @@ async def list_projects_async( request = models.ListProjectsRequest( level=level, + q=q, ordering=ordering, page=page, page_size=page_size, @@ -258,13 +264,18 @@ def get_project( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.ProjectDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.ProjectErrorData, http_res) raise models.ProjectError(response_data, http_res) @@ -344,13 +355,18 @@ async def get_project_async( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.ProjectDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.ProjectErrorData, http_res) raise models.ProjectError(response_data, http_res) diff --git a/src/owasp_nest/releases.py b/src/owasp_nest/releases.py index 5aab1f2..e528147 100644 --- a/src/owasp_nest/releases.py +++ b/src/owasp_nest/releases.py @@ -276,13 +276,18 @@ def get_release( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.ReleaseDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.ReleaseErrorData, http_res) raise models.ReleaseError(response_data, http_res) @@ -368,13 +373,18 @@ async def get_release_async( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.ReleaseDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.ReleaseErrorData, http_res) raise models.ReleaseError(response_data, http_res) diff --git a/src/owasp_nest/repositories.py b/src/owasp_nest/repositories.py index 344fe7e..735aeb3 100644 --- a/src/owasp_nest/repositories.py +++ b/src/owasp_nest/repositories.py @@ -261,13 +261,18 @@ def get_repository( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.RepositoryDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response( models.RepositoryErrorData, http_res @@ -352,13 +357,18 @@ async def get_repository_async( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.RepositoryDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response( models.RepositoryErrorData, http_res diff --git a/src/owasp_nest/sponsors.py b/src/owasp_nest/sponsors.py index d449257..a9ebc67 100644 --- a/src/owasp_nest/sponsors.py +++ b/src/owasp_nest/sponsors.py @@ -270,13 +270,18 @@ def get_sponsor( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.SponsorDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.SponsorErrorData, http_res) raise models.SponsorError(response_data, http_res) @@ -356,13 +361,18 @@ async def get_sponsor_async( security_source=self.sdk_configuration.security, ), request=req, - error_status_codes=["404", "4XX", "5XX"], + error_status_codes=["400", "404", "4XX", "5XX"], retry_config=retry_config, ) response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return unmarshal_json_response(models.SponsorDetail, http_res) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + models.ValidationErrorSchemaData, http_res + ) + raise models.ValidationErrorSchema(response_data, http_res) if utils.match_response(http_res, "404", "application/json"): response_data = unmarshal_json_response(models.SponsorErrorData, http_res) raise models.SponsorError(response_data, http_res) diff --git a/src/owasp_nest/types/basemodel.py b/src/owasp_nest/types/basemodel.py index 231c2e3..a9a640a 100644 --- a/src/owasp_nest/types/basemodel.py +++ b/src/owasp_nest/types/basemodel.py @@ -2,7 +2,8 @@ from pydantic import ConfigDict, model_serializer from pydantic import BaseModel as PydanticBaseModel -from typing import TYPE_CHECKING, Literal, Optional, TypeVar, Union +from pydantic_core import core_schema +from typing import TYPE_CHECKING, Any, Literal, Optional, TypeVar, Union from typing_extensions import TypeAliasType, TypeAlias @@ -35,5 +36,42 @@ def __bool__(self) -> Literal[False]: "OptionalNullable", Union[Optional[Nullable[T]], Unset], type_params=(T,) ) -UnrecognizedInt: TypeAlias = int -UnrecognizedStr: TypeAlias = str + +class UnrecognizedStr(str): + @classmethod + def __get_pydantic_core_schema__(cls, _source_type: Any, _handler: Any) -> core_schema.CoreSchema: + # Make UnrecognizedStr only work in lax mode, not strict mode + # This makes it a "fallback" option when more specific types (like Literals) don't match + def validate_lax(v: Any) -> 'UnrecognizedStr': + if isinstance(v, cls): + return v + return cls(str(v)) + + # Use lax_or_strict_schema where strict always fails + # This forces Pydantic to prefer other union members in strict mode + # and only fall back to UnrecognizedStr in lax mode + return core_schema.lax_or_strict_schema( + lax_schema=core_schema.chain_schema([ + core_schema.str_schema(), + core_schema.no_info_plain_validator_function(validate_lax) + ]), + strict_schema=core_schema.none_schema(), # Always fails in strict mode + ) + + +class UnrecognizedInt(int): + @classmethod + def __get_pydantic_core_schema__(cls, _source_type: Any, _handler: Any) -> core_schema.CoreSchema: + # Make UnrecognizedInt only work in lax mode, not strict mode + # This makes it a "fallback" option when more specific types (like Literals) don't match + def validate_lax(v: Any) -> 'UnrecognizedInt': + if isinstance(v, cls): + return v + return cls(int(v)) + return core_schema.lax_or_strict_schema( + lax_schema=core_schema.chain_schema([ + core_schema.int_schema(), + core_schema.no_info_plain_validator_function(validate_lax) + ]), + strict_schema=core_schema.none_schema(), # Always fails in strict mode + ) diff --git a/src/owasp_nest/utils/__init__.py b/src/owasp_nest/utils/__init__.py index 56164cf..15394a0 100644 --- a/src/owasp_nest/utils/__init__.py +++ b/src/owasp_nest/utils/__init__.py @@ -1,10 +1,19 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Callable, TypeVar from importlib import import_module +import asyncio import builtins import sys +_T = TypeVar("_T") + + +async def run_sync_in_thread(func: Callable[..., _T], *args) -> _T: + """Run a synchronous function in a thread pool to avoid blocking the event loop.""" + return await asyncio.to_thread(func, *args) + + if TYPE_CHECKING: from .annotations import get_discriminator from .datetimes import parse_datetime @@ -41,7 +50,6 @@ validate_decimal, validate_float, validate_int, - validate_open_enum, ) from .url import generate_url, template_url, remove_suffix from .values import ( @@ -102,7 +110,6 @@ "validate_const", "validate_float", "validate_int", - "validate_open_enum", "cast_partial", ] @@ -155,7 +162,6 @@ "validate_const": ".serializers", "validate_float": ".serializers", "validate_int": ".serializers", - "validate_open_enum": ".serializers", "cast_partial": ".values", } diff --git a/src/owasp_nest/utils/enums.py b/src/owasp_nest/utils/enums.py index c3bc13c..3324e1b 100644 --- a/src/owasp_nest/utils/enums.py +++ b/src/owasp_nest/utils/enums.py @@ -2,6 +2,10 @@ import enum import sys +from typing import Any + +from pydantic_core import core_schema + class OpenEnumMeta(enum.EnumMeta): # The __call__ method `boundary` kwarg was added in 3.11 and must be present @@ -72,3 +76,59 @@ def __call__( ) except ValueError: return value + + def __new__(mcs, name, bases, namespace, **kwargs): + cls = super().__new__(mcs, name, bases, namespace, **kwargs) + + # Add __get_pydantic_core_schema__ to make open enums work correctly + # in union discrimination. In strict mode (used by Pydantic for unions), + # only known enum values match. In lax mode, unknown values are accepted. + def __get_pydantic_core_schema__( + cls_inner: Any, _source_type: Any, _handler: Any + ) -> core_schema.CoreSchema: + # Create a validator that only accepts known enum values (for strict mode) + def validate_strict(v: Any) -> Any: + if isinstance(v, cls_inner): + return v + # Use the parent EnumMeta's __call__ which raises ValueError for unknown values + return enum.EnumMeta.__call__(cls_inner, v) + + # Create a lax validator that accepts unknown values + def validate_lax(v: Any) -> Any: + if isinstance(v, cls_inner): + return v + try: + return enum.EnumMeta.__call__(cls_inner, v) + except ValueError: + # Return the raw value for unknown enum values + return v + + # Determine the base type schema (str or int) + is_int_enum = False + for base in cls_inner.__mro__: + if base is int: + is_int_enum = True + break + if base is str: + break + + base_schema = ( + core_schema.int_schema() + if is_int_enum + else core_schema.str_schema() + ) + + # Use lax_or_strict_schema: + # - strict mode: only known enum values match (raises ValueError for unknown) + # - lax mode: accept any value, return enum member or raw value + return core_schema.lax_or_strict_schema( + lax_schema=core_schema.chain_schema( + [base_schema, core_schema.no_info_plain_validator_function(validate_lax)] + ), + strict_schema=core_schema.chain_schema( + [base_schema, core_schema.no_info_plain_validator_function(validate_strict)] + ), + ) + + setattr(cls, "__get_pydantic_core_schema__", classmethod(__get_pydantic_core_schema__)) + return cls diff --git a/src/owasp_nest/utils/eventstreaming.py b/src/owasp_nest/utils/eventstreaming.py index 0969899..f2052fc 100644 --- a/src/owasp_nest/utils/eventstreaming.py +++ b/src/owasp_nest/utils/eventstreaming.py @@ -2,7 +2,9 @@ import re import json +from dataclasses import dataclass, asdict from typing import ( + Any, Callable, Generic, TypeVar, @@ -22,6 +24,7 @@ class EventStream(Generic[T]): client_ref: Optional[object] response: httpx.Response generator: Generator[T, None, None] + _closed: bool def __init__( self, @@ -33,17 +36,21 @@ def __init__( self.response = response self.generator = stream_events(response, decoder, sentinel) self.client_ref = client_ref + self._closed = False def __iter__(self): return self def __next__(self): + if self._closed: + raise StopIteration return next(self.generator) def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): + self._closed = True self.response.close() @@ -53,6 +60,7 @@ class EventStreamAsync(Generic[T]): client_ref: Optional[object] response: httpx.Response generator: AsyncGenerator[T, None] + _closed: bool def __init__( self, @@ -64,33 +72,45 @@ def __init__( self.response = response self.generator = stream_events_async(response, decoder, sentinel) self.client_ref = client_ref + self._closed = False def __aiter__(self): return self async def __anext__(self): + if self._closed: + raise StopAsyncIteration return await self.generator.__anext__() async def __aenter__(self): return self async def __aexit__(self, exc_type, exc_val, exc_tb): + self._closed = True await self.response.aclose() +@dataclass class ServerEvent: id: Optional[str] = None event: Optional[str] = None - data: Optional[str] = None + data: Any = None retry: Optional[int] = None MESSAGE_BOUNDARIES = [ b"\r\n\r\n", - b"\n\n", + b"\r\n\r", + b"\r\n\n", + b"\r\r\n", + b"\n\r\n", b"\r\r", + b"\n\r", + b"\n\n", ] +UTF8_BOM = b"\xef\xbb\xbf" + async def stream_events_async( response: httpx.Response, @@ -99,14 +119,10 @@ async def stream_events_async( ) -> AsyncGenerator[T, None]: buffer = bytearray() position = 0 - discard = False + event_id: Optional[str] = None async for chunk in response.aiter_bytes(): - # We've encountered the sentinel value and should no longer process - # incoming data. Instead we throw new data away until the server closes - # the connection. - if discard: - continue - + if len(buffer) == 0 and chunk.startswith(UTF8_BOM): + chunk = chunk[len(UTF8_BOM) :] buffer += chunk for i in range(position, len(buffer)): char = buffer[i : i + 1] @@ -121,15 +137,22 @@ async def stream_events_async( block = buffer[position:i] position = i + len(seq) - event, discard = _parse_event(block, decoder, sentinel) + event, discard, event_id = _parse_event( + raw=block, decoder=decoder, sentinel=sentinel, event_id=event_id + ) if event is not None: yield event + if discard: + await response.aclose() + return if position > 0: buffer = buffer[position:] position = 0 - event, discard = _parse_event(buffer, decoder, sentinel) + event, discard, _ = _parse_event( + raw=buffer, decoder=decoder, sentinel=sentinel, event_id=event_id + ) if event is not None: yield event @@ -141,14 +164,10 @@ def stream_events( ) -> Generator[T, None, None]: buffer = bytearray() position = 0 - discard = False + event_id: Optional[str] = None for chunk in response.iter_bytes(): - # We've encountered the sentinel value and should no longer process - # incoming data. Instead we throw new data away until the server closes - # the connection. - if discard: - continue - + if len(buffer) == 0 and chunk.startswith(UTF8_BOM): + chunk = chunk[len(UTF8_BOM) :] buffer += chunk for i in range(position, len(buffer)): char = buffer[i : i + 1] @@ -163,22 +182,33 @@ def stream_events( block = buffer[position:i] position = i + len(seq) - event, discard = _parse_event(block, decoder, sentinel) + event, discard, event_id = _parse_event( + raw=block, decoder=decoder, sentinel=sentinel, event_id=event_id + ) if event is not None: yield event + if discard: + response.close() + return if position > 0: buffer = buffer[position:] position = 0 - event, discard = _parse_event(buffer, decoder, sentinel) + event, discard, _ = _parse_event( + raw=buffer, decoder=decoder, sentinel=sentinel, event_id=event_id + ) if event is not None: yield event def _parse_event( - raw: bytearray, decoder: Callable[[str], T], sentinel: Optional[str] = None -) -> Tuple[Optional[T], bool]: + *, + raw: bytearray, + decoder: Callable[[str], T], + sentinel: Optional[str] = None, + event_id: Optional[str] = None, +) -> Tuple[Optional[T], bool, Optional[str]]: block = raw.decode() lines = re.split(r"\r?\n|\r", block) publish = False @@ -189,13 +219,16 @@ def _parse_event( continue delim = line.find(":") - if delim <= 0: + if delim == 0: continue - field = line[0:delim] - value = line[delim + 1 :] if delim < len(line) - 1 else "" - if len(value) and value[0] == " ": - value = value[1:] + field = line + value = "" + if delim > 0: + field = line[0:delim] + value = line[delim + 1 :] if delim < len(line) - 1 else "" + if len(value) and value[0] == " ": + value = value[1:] if field == "event": event.event = value @@ -204,37 +237,36 @@ def _parse_event( data += value + "\n" publish = True elif field == "id": - event.id = value publish = True + if "\x00" not in value: + event_id = value elif field == "retry": - event.retry = int(value) if value.isdigit() else None + if value.isdigit(): + event.retry = int(value) publish = True + event.id = event_id + if sentinel and data == f"{sentinel}\n": - return None, True + return None, True, event_id if data: data = data[:-1] - event.data = data - - data_is_primitive = ( - data.isnumeric() or data == "true" or data == "false" or data == "null" - ) - data_is_json = ( - data.startswith("{") or data.startswith("[") or data.startswith('"') - ) - - if data_is_primitive or data_is_json: - try: - event.data = json.loads(data) - except Exception: - pass + try: + event.data = json.loads(data) + except json.JSONDecodeError: + event.data = data out = None if publish: - out = decoder(json.dumps(event.__dict__)) - - return out, False + out_dict = { + k: v + for k, v in asdict(event).items() + if v is not None or (k == "data" and data) + } + out = decoder(json.dumps(out_dict)) + + return out, False, event_id def _peek_sequence(position: int, buffer: bytearray, sequence: bytes): diff --git a/src/owasp_nest/utils/requestbodies.py b/src/owasp_nest/utils/requestbodies.py index d5240dd..1de32b6 100644 --- a/src/owasp_nest/utils/requestbodies.py +++ b/src/owasp_nest/utils/requestbodies.py @@ -44,15 +44,15 @@ def serialize_request_body( serialized_request_body = SerializedRequestBody(media_type) - if re.match(r"(application|text)\/.*?\+*json.*", media_type) is not None: + if re.match(r"^(application|text)\/([^+]+\+)*json.*", media_type) is not None: serialized_request_body.content = marshal_json(request_body, request_body_type) - elif re.match(r"multipart\/.*", media_type) is not None: + elif re.match(r"^multipart\/.*", media_type) is not None: ( serialized_request_body.media_type, serialized_request_body.data, serialized_request_body.files, ) = serialize_multipart_form(media_type, request_body) - elif re.match(r"application\/x-www-form-urlencoded.*", media_type) is not None: + elif re.match(r"^application\/x-www-form-urlencoded.*", media_type) is not None: serialized_request_body.data = serialize_form_data(request_body) elif isinstance(request_body, (bytes, bytearray, io.BytesIO, io.BufferedReader)): serialized_request_body.content = request_body diff --git a/src/owasp_nest/utils/security.py b/src/owasp_nest/utils/security.py index 295a3f4..17996bd 100644 --- a/src/owasp_nest/utils/security.py +++ b/src/owasp_nest/utils/security.py @@ -135,6 +135,8 @@ def _parse_security_scheme_value( elif scheme_type == "http": if sub_type == "bearer": headers[header_name] = _apply_bearer(value) + elif sub_type == "basic": + headers[header_name] = value elif sub_type == "custom": return else: diff --git a/src/owasp_nest/utils/serializers.py b/src/owasp_nest/utils/serializers.py index 378a14c..14321eb 100644 --- a/src/owasp_nest/utils/serializers.py +++ b/src/owasp_nest/utils/serializers.py @@ -102,26 +102,6 @@ def validate_int(b): return int(b) -def validate_open_enum(is_int: bool): - def validate(e): - if e is None: - return None - - if isinstance(e, Unset): - return e - - if is_int: - if not isinstance(e, int): - raise ValueError("Expected int") - else: - if not isinstance(e, str): - raise ValueError("Expected string") - - return e - - return validate - - def validate_const(v): def validate(c): # Optional[T] is a Union[T, None] diff --git a/uv.lock b/uv.lock index 1906330..830d363 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,6 @@ version = 1 revision = 3 -requires-python = ">=3.9.2" +requires-python = ">=3.10" resolution-markers = [ "python_full_version >= '3.12'", "python_full_version == '3.11.*'", @@ -181,12 +181,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/8b/801aa06445d2de3895f59e476f38f3f8d610ef5d6908245f07d002676cbf/mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036", size = 12402541, upload-time = "2025-02-05T03:49:57.623Z" }, { url = "https://files.pythonhosted.org/packages/c7/67/5a4268782eb77344cc613a4cf23540928e41f018a9a1ec4c6882baf20ab8/mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357", size = 12494348, upload-time = "2025-02-05T03:48:52.361Z" }, { url = "https://files.pythonhosted.org/packages/83/3e/57bb447f7bbbfaabf1712d96f9df142624a386d98fb026a761532526057e/mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf", size = 9373648, upload-time = "2025-02-05T03:49:11.395Z" }, - { url = "https://files.pythonhosted.org/packages/5a/fa/79cf41a55b682794abe71372151dbbf856e3008f6767057229e6649d294a/mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078", size = 10737129, upload-time = "2025-02-05T03:50:24.509Z" }, - { url = "https://files.pythonhosted.org/packages/d3/33/dd8feb2597d648de29e3da0a8bf4e1afbda472964d2a4a0052203a6f3594/mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba", size = 9856335, upload-time = "2025-02-05T03:49:36.398Z" }, - { url = "https://files.pythonhosted.org/packages/e4/b5/74508959c1b06b96674b364ffeb7ae5802646b32929b7701fc6b18447592/mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5", size = 11611935, upload-time = "2025-02-05T03:49:14.154Z" }, - { url = "https://files.pythonhosted.org/packages/6c/53/da61b9d9973efcd6507183fdad96606996191657fe79701b2c818714d573/mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b", size = 12365827, upload-time = "2025-02-05T03:48:59.458Z" }, - { url = "https://files.pythonhosted.org/packages/c1/72/965bd9ee89540c79a25778cc080c7e6ef40aa1eeac4d52cec7eae6eb5228/mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2", size = 12541924, upload-time = "2025-02-05T03:50:03.12Z" }, - { url = "https://files.pythonhosted.org/packages/46/d0/f41645c2eb263e6c77ada7d76f894c580c9ddb20d77f0c24d34273a4dab2/mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980", size = 9271176, upload-time = "2025-02-05T03:50:10.86Z" }, { url = "https://files.pythonhosted.org/packages/09/4e/a7d65c7322c510de2c409ff3828b03354a7c43f5a8ed458a7a131b41c7b9/mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e", size = 2221777, upload-time = "2025-02-05T03:50:08.348Z" }, ] @@ -210,7 +204,7 @@ wheels = [ [[package]] name = "owasp-nest" -version = "0.3.7" +version = "0.4.0" source = { editable = "." } dependencies = [ { name = "httpcore" }, @@ -330,19 +324,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, - { url = "https://files.pythonhosted.org/packages/53/ea/bbe9095cdd771987d13c82d104a9c8559ae9aec1e29f139e286fd2e9256e/pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d", size = 2028677, upload-time = "2025-04-23T18:32:27.227Z" }, - { url = "https://files.pythonhosted.org/packages/49/1d/4ac5ed228078737d457a609013e8f7edc64adc37b91d619ea965758369e5/pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954", size = 1864735, upload-time = "2025-04-23T18:32:29.019Z" }, - { url = "https://files.pythonhosted.org/packages/23/9a/2e70d6388d7cda488ae38f57bc2f7b03ee442fbcf0d75d848304ac7e405b/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb", size = 1898467, upload-time = "2025-04-23T18:32:31.119Z" }, - { url = "https://files.pythonhosted.org/packages/ff/2e/1568934feb43370c1ffb78a77f0baaa5a8b6897513e7a91051af707ffdc4/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7", size = 1983041, upload-time = "2025-04-23T18:32:33.655Z" }, - { url = "https://files.pythonhosted.org/packages/01/1a/1a1118f38ab64eac2f6269eb8c120ab915be30e387bb561e3af904b12499/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4", size = 2136503, upload-time = "2025-04-23T18:32:35.519Z" }, - { url = "https://files.pythonhosted.org/packages/5c/da/44754d1d7ae0f22d6d3ce6c6b1486fc07ac2c524ed8f6eca636e2e1ee49b/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b", size = 2736079, upload-time = "2025-04-23T18:32:37.659Z" }, - { url = "https://files.pythonhosted.org/packages/4d/98/f43cd89172220ec5aa86654967b22d862146bc4d736b1350b4c41e7c9c03/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3", size = 2006508, upload-time = "2025-04-23T18:32:39.637Z" }, - { url = "https://files.pythonhosted.org/packages/2b/cc/f77e8e242171d2158309f830f7d5d07e0531b756106f36bc18712dc439df/pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a", size = 2113693, upload-time = "2025-04-23T18:32:41.818Z" }, - { url = "https://files.pythonhosted.org/packages/54/7a/7be6a7bd43e0a47c147ba7fbf124fe8aaf1200bc587da925509641113b2d/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782", size = 2074224, upload-time = "2025-04-23T18:32:44.033Z" }, - { url = "https://files.pythonhosted.org/packages/2a/07/31cf8fadffbb03be1cb520850e00a8490c0927ec456e8293cafda0726184/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9", size = 2245403, upload-time = "2025-04-23T18:32:45.836Z" }, - { url = "https://files.pythonhosted.org/packages/b6/8d/bbaf4c6721b668d44f01861f297eb01c9b35f612f6b8e14173cb204e6240/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e", size = 2242331, upload-time = "2025-04-23T18:32:47.618Z" }, - { url = "https://files.pythonhosted.org/packages/bb/93/3cc157026bca8f5006250e74515119fcaa6d6858aceee8f67ab6dc548c16/pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9", size = 1910571, upload-time = "2025-04-23T18:32:49.401Z" }, - { url = "https://files.pythonhosted.org/packages/5b/90/7edc3b2a0d9f0dda8806c04e511a67b0b7a41d2187e2003673a996fb4310/pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3", size = 1956504, upload-time = "2025-04-23T18:32:51.287Z" }, { url = "https://files.pythonhosted.org/packages/30/68/373d55e58b7e83ce371691f6eaa7175e3a24b956c44628eb25d7da007917/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa", size = 2023982, upload-time = "2025-04-23T18:32:53.14Z" }, { url = "https://files.pythonhosted.org/packages/a4/16/145f54ac08c96a63d8ed6442f9dec17b2773d19920b627b18d4f10a061ea/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29", size = 1858412, upload-time = "2025-04-23T18:32:55.52Z" }, { url = "https://files.pythonhosted.org/packages/41/b1/c6dc6c3e2de4516c0bb2c46f6a373b91b5660312342a0cf5826e38ad82fa/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d", size = 1892749, upload-time = "2025-04-23T18:32:57.546Z" }, @@ -361,15 +342,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" }, { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" }, { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757, upload-time = "2025-04-23T18:33:30.645Z" }, - { url = "https://files.pythonhosted.org/packages/08/98/dbf3fdfabaf81cda5622154fda78ea9965ac467e3239078e0dcd6df159e7/pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101", size = 2024034, upload-time = "2025-04-23T18:33:32.843Z" }, - { url = "https://files.pythonhosted.org/packages/8d/99/7810aa9256e7f2ccd492590f86b79d370df1e9292f1f80b000b6a75bd2fb/pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64", size = 1858578, upload-time = "2025-04-23T18:33:34.912Z" }, - { url = "https://files.pythonhosted.org/packages/d8/60/bc06fa9027c7006cc6dd21e48dbf39076dc39d9abbaf718a1604973a9670/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d", size = 1892858, upload-time = "2025-04-23T18:33:36.933Z" }, - { url = "https://files.pythonhosted.org/packages/f2/40/9d03997d9518816c68b4dfccb88969756b9146031b61cd37f781c74c9b6a/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535", size = 2068498, upload-time = "2025-04-23T18:33:38.997Z" }, - { url = "https://files.pythonhosted.org/packages/d8/62/d490198d05d2d86672dc269f52579cad7261ced64c2df213d5c16e0aecb1/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d", size = 2108428, upload-time = "2025-04-23T18:33:41.18Z" }, - { url = "https://files.pythonhosted.org/packages/9a/ec/4cd215534fd10b8549015f12ea650a1a973da20ce46430b68fc3185573e8/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6", size = 2069854, upload-time = "2025-04-23T18:33:43.446Z" }, - { url = "https://files.pythonhosted.org/packages/1a/1a/abbd63d47e1d9b0d632fee6bb15785d0889c8a6e0a6c3b5a8e28ac1ec5d2/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca", size = 2237859, upload-time = "2025-04-23T18:33:45.56Z" }, - { url = "https://files.pythonhosted.org/packages/80/1c/fa883643429908b1c90598fd2642af8839efd1d835b65af1f75fba4d94fe/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039", size = 2239059, upload-time = "2025-04-23T18:33:47.735Z" }, - { url = "https://files.pythonhosted.org/packages/d4/29/3cade8a924a61f60ccfa10842f75eb12787e1440e2b8660ceffeb26685e7/pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27", size = 2066661, upload-time = "2025-04-23T18:33:49.995Z" }, ] [[package]] @@ -385,7 +357,6 @@ dependencies = [ { name = "platformdirs" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "tomlkit" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9a/e9/60280b14cc1012794120345ce378504cf17409e38cd88f455dc24e0ad6b5/pylint-3.2.3.tar.gz", hash = "sha256:02f6c562b215582386068d52a30f520d84fdbcf2a95fc7e855b816060d048b60", size = 1506739, upload-time = "2024-06-06T14:19:17.955Z" } wheels = [