From a9dc03ce8a176d19977ff94f9a49d3e1ca415c5c Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 23:51:02 +0000 Subject: [PATCH] SDK Generation --- .fern/metadata.json | 9 + .github/workflows/ci.yml | 10 +- LICENSE | 189 ------------------ README.md | 3 +- poetry.lock | 103 +++++----- pyproject.toml | 20 +- requirements.txt | 1 - src/anduril/core/client_wrapper.py | 3 +- src/anduril/core/http_sse/__init__.py | 42 ++++ src/anduril/core/http_sse/_api.py | 112 +++++++++++ src/anduril/core/http_sse/_decoders.py | 61 ++++++ src/anduril/core/http_sse/_exceptions.py | 7 + src/anduril/core/http_sse/_models.py | 17 ++ src/anduril/core/pydantic_utilities.py | 4 +- src/anduril/entities/raw_client.py | 36 +++- .../types/stream_entities_response.py | 8 +- src/anduril/types/agent_request.py | 5 - src/anduril/types/cancel_request.py | 2 +- src/anduril/types/entity.py | 3 +- src/anduril/types/entity_event.py | 4 +- src/anduril/types/entity_event_response.py | 4 - src/anduril/types/entity_stream_event.py | 5 - src/anduril/types/execute_request.py | 5 - src/anduril/types/override.py | 3 +- src/anduril/types/overrides.py | 3 +- src/anduril/types/pose.py | 6 +- src/anduril/types/relations.py | 2 +- src/anduril/types/status.py | 21 +- src/anduril/types/task.py | 5 +- src/anduril/types/task_entity.py | 4 +- src/anduril/types/task_query_results.py | 5 - 31 files changed, 364 insertions(+), 338 deletions(-) create mode 100644 .fern/metadata.json delete mode 100644 LICENSE create mode 100644 src/anduril/core/http_sse/__init__.py create mode 100644 src/anduril/core/http_sse/_api.py create mode 100644 src/anduril/core/http_sse/_decoders.py create mode 100644 src/anduril/core/http_sse/_exceptions.py create mode 100644 src/anduril/core/http_sse/_models.py diff --git a/.fern/metadata.json b/.fern/metadata.json new file mode 100644 index 0000000..758636f --- /dev/null +++ b/.fern/metadata.json @@ -0,0 +1,9 @@ +{ + "cliVersion": "0.113.1", + "generatorName": "fernapi/fern-python-sdk", + "generatorVersion": "99.99.99", + "generatorConfig": { + "client_class_name": "Lattice", + "package_name": "anduril" + } +} \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9818c03..16b3b78 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,8 +1,6 @@ name: ci - on: [push] jobs: - compile: runs-on: ubuntu-latest steps: - name: Checkout repo @@ -10,8 +8,6 @@ jobs: - name: Set up python uses: actions/setup-python@v4 with: - python-version: 3.8 - - name: Bootstrap poetry run: | curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 - name: Install dependencies @@ -55,7 +51,7 @@ jobs: - name: Publish to pypi run: | poetry config repositories.remote https://upload.pypi.org/legacy/ - poetry --no-interaction -v publish --build --repository remote --username "$PYPI_USERNAME" --password "$PYPI_PASSWORD" + poetry --no-interaction -v publish --build --repository remote --username "$__token__" --password "$" env: - PYPI_USERNAME: ${{ secrets.PYPI_USERNAME }} - PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + __token__: ${{ secrets.__token__ }} + : ${{ secrets. }} diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 9623e9f..0000000 --- a/LICENSE +++ /dev/null @@ -1,189 +0,0 @@ -# Anduril Lattice Software Development Kit License Agreement - -## Terms and Conditions - -This is the Anduril Lattice Software Development Kit (SDK) License Agreement (the “License Agreement”). - -1. **Introduction** - - 1.1 "Anduril" means Anduril Industries, Inc., organized under the laws of the State of Delaware, USA, and operating under the laws of - the USA with principal place of business at 1400 Anduril, Costa Mesa, California 92626, USA. - - 1.2 "Lattice" means the Anduril Lattice™ software stack for devices, as made available by Anduril, as updated from time to time. - - 1.3 The Anduril Lattice Software Development Kit (referred to in the License Agreement as the "SDK" and specifically including the - Lattice system files, packaged APIs, and Anduril APIs add-ons) is licensed to you subject to the terms of the License Agreement. - The License Agreement forms a legally binding contract between you and Anduril in relation to your use of the SDK. SDK, as used - herein, also includes any software libraries and/or packages that reference this License. - - 1.4 A "compatible implementation" means any use that (i) is compatible with Lattice; or (ii) successfully is validated by Anduril to be - compatible with Lattice. The determination of a compatible implementation is solely at the discretion of Anduril. - -2. **Accepting this License Agreement** - - - 2.1 In order to use the SDK, you must first agree to the License Agreement. You may not use the SDK if you do not accept the License -Agreement. - - 2.2 By clicking to accept and/or using this SDK, you hereby agree to the terms of the License Agreement. - - 2.3 You may not use the SDK and may not accept the License Agreement if you are a person barred from receiving the SDK under the -laws of the United States or other countries, including the country in which you are resident or from which you use the SDK. - - 2.4 If you are agreeing to be bound by the License Agreement on behalf of your employer or other entity, you represent and warrant that -you have full legal authority to bind your employer or such entity to the License Agreement. If you do not have the requisite authority, you -may not accept the License Agreement or use the SDK on behalf of your employer or other entity. Use of the SDK on hardware owned -by an entity such as your employer binds your employer to this License Agreement. - -3. **SDK License from Anduril** - - - 3.1 Subject to the terms of the License Agreement, Anduril grants you a limited, revocable, worldwide, royalty-free, non-assignable, - non- exclusive, and non-sublicensable license to use the SDK, or the software referencing this License Agreement, solely to develop - applications for compatible implementations of Anduril technology including without limitation systems, hardware and software such as Anduril Lattice. - - 3.2 You may not use this SDK to develop applications for other platforms (including non-compatible implementations of Lattice) or to -develop another SDK. You are of course free to develop applications for other platforms, including non-compatible implementations of -Lattice, provided that this SDK is not used for that purpose. - - 3.3 You agree that Anduril or third parties own all legal right, title and interest in and to the SDK, including any Intellectual Property Rights -that subsist in the SDK. "Intellectual Property Rights" means any and all rights under patent law, copyright law, trade secret law, trademark -law, and any and all other proprietary rights. Anduril reserves all rights not expressly granted to you. - - 3.4 You may not use the SDK for any purpose not expressly permitted by the License Agreement. Except to the extent required by -applicable third party licenses, you may not copy (except for backup purposes), modify, adapt, redistribute, de compile, reverse engineer, -disassemble, or create derivative works of the SDK or any part of the SDK. - - 3.5 Use, reproduction and distribution of components of the SDK licensed under an open-source software license are governed solely by -the terms of that open-source software license and not the License Agreement. - - 3.6 You agree that the form and nature of the SDK that Anduril provides may change without prior notice to you and that future versions -of the SDK may be incompatible with applications developed on previous versions of the SDK. You agree that Anduril may stop -(permanently or temporarily) providing the SDK (or any features within the SDK) to you or to users generally at Anduril's sole discretion, -without prior notice to you. - - 3.7 Nothing in the License Agreement gives you a right to use any of Anduril's trade names, trademarks, service marks, logos, domain -names, or other distinctive brand features. - - 3.8 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that -may be affixed to or contained within the SDK. - -4. **Use of the SDK by You** - - - 4.1 Anduril agrees that it obtains no right, title or interest from you (or your licensors) under the License Agreement in or to any software -applications that you develop using the SDK, including any intellectual property rights that subsist in those applications. - - 4.2 You agree to use the SDK and write applications only for purposes that are permitted by (a) the License Agreement and (b) any -applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the -export of data or software to and from the United States or other relevant countries). - - 4.3 You agree that if you use the SDK to develop applications for Anduril Lattice users, you will protect the privacy and legal rights of -those users. If your application stores personal or sensitive information, it must do so securely. You may not use a third-party’s Lattice -account information or credentials to access Lattice. - - 4.4 You agree that you will not engage in any activity with the SDK, including the development or distribution of an application, that -interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of any -third party including, but not limited to, Anduril or any fixed or mobile communications carrier. - - 4.5 You agree that you are solely responsible for (and that Anduril has no responsibility to you or to any third party for) any data, content, -or resources that you create, transmit or display through Anduril Lattice and/or applications for Lattice, and for the consequences of your -actions (including any loss or damage which Anduril may suffer) by doing so. - - 4.6 You agree that you are solely responsible for (and that Anduril has no responsibility to you or to any third party for) any breach of your -obligations under the License Agreement, any applicable third party contract or Terms of Service, or any applicable law or regulation, and -for the consequences (including any loss or damage which Anduril or any third party may suffer) of any such breach. - -5. **Your Developer Credentials** - - - 5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be issued to you by -Anduril or which you may choose yourself and that you will be solely responsible for all applications that are developed under your -developer credentials. - -6. **Privacy and Information** - - - 6.1 In order to continually innovate and improve the SDK, Anduril may collect certain usage statistics from the software including but not -limited to a unique identifier, associated IP address, version number of the software, and information on which tools and/or services in -the SDK are being used and how they are being used. - - 6.2 Anonymized and aggregated sets of the data may be used or shared by Anduril to improve the SDK. - -7. **Third Party Applications** - - - 7.1 If you use the SDK to run applications developed by a third party or that access data, content or resources provided by a third party, -you agree that Anduril is not responsible for those applications, data, content, or resources. You understand that all data, content or -resources which you may access through such third party applications are the sole responsibility of the person from which they originated -and that Anduril is not liable for any loss or damage that you may experience as a result of the use or access of any of those third party -applications, data, content, or resources. - - 7.2 You should be aware the data, content, and resources presented to you through such a third party application may be protected by -intellectual property rights which are owned by the providers (or by other persons or companies on their behalf). You may not modify, -rent, lease, loan, sell, distribute or create derivative works based on these data, content, or resources (either in whole or in part) unless -you have been specifically given permission to do so by the relevant owners. - - 7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to separate terms between -you and the relevant third party. In that case, the License Agreement does not affect your legal relationship with these third parties. - -8. **Using Lattice APIs** - - - 8.1 Anduril Data APIs - - 8.1.1 If you use any API to retrieve data, you acknowledge that the data may be protected by intellectual property rights which are owned -by Anduril or those parties that provide the data (or by other persons or companies on their behalf). Your use of any such API may be -subject to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this data -(either in whole or in part) unless allowed by the relevant owner and/or terms of service. - - 8.1.2 If you use any API to retrieve a user's data, you acknowledge and agree that you shall retrieve data only with the user's explicit -consent and only when, and for the limited purposes for which, the user has given you permission to do so. - -9. **Terminating this License Agreement** - - - 9.1 The License Agreement will continue to apply until terminated by either you or Anduril as set out below. - - 9.2 If you want to terminate the License Agreement, you may do so by ceasing your use of the SDK and any relevant developer -credentials. - - 9.3 Anduril may at any time, terminate the License Agreement with you if: (i) you have breached any provision of the License Agreement; -or (ii) Anduril is required to do so by law; or (iii) the partner with whom Anduril offered certain parts of SDK (such as APIs) to you has -terminated its relationship with Anduril or ceased to offer certain parts of the SDK to you; or (iv) Anduril decides to no longer provide the -SDK to you, or (v) in Anduril's sole discretion, it is no longer commercially viable to provide the SDK. - - 9.4 When the License Agreement comes to an end, you shall delete all copies in your possession of the SDK, and discontinue using the -SDK and related APIs.The provisions of paragraph 14.7 shall continue to apply indefinitely. - -10. **DISCLAIMER OF WARRANTIES** - - - 10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE SDK IS AT YOUR SOLE RISK AND THAT THE SDK -IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM ANDURIL. - - 10.2 YOUR USE OF THE SDK AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE -SDK IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER -SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE. - - 10.3 ANDURIL FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR -IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - -11. **LIMITATION OF LIABILITY** - - - 11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT ANDURIL, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS -SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER -OR NOT ANDURIL OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY -OF ANY SUCH LOSSES ARISING. - -12. **Indemnification** - - - 12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Anduril, its affiliates and their respective -directors, officers, employees and agents from and against any and all claims, actions, suits or proceedings, as well as any and all losses, -liabilities, damages, costs and expenses (including reasonable attorneys fees) arising out of or accruing from (a) your use of the SDK, -(b) any application you develop on the SDK that infringes any copyright, trademark, trade secret, trade dress, patent or other intellectual -property right of any person or defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you with -the License Agreement. - -13. **Changes to the License Agreement** - - - 13.1 Anduril may make changes to the License Agreement as it distributes new versions of the SDK. When these changes are made, -Anduril will make a new version of the License Agreement available on the website where the SDK is made available. - -14. **General Legal Terms** - - - 14.1 The License Agreement constitutes the whole legal agreement between you and Anduril and governs your use of the SDK (excluding -any services which Anduril may provide to you under a separate written agreement), and completely replaces any prior agreements -between you and Anduril in relation to the SDK. - - 14.2 You agree that if Anduril does not exercise or enforce any legal right or remedy which is contained in the License Agreement (or -which Anduril has the benefit of under any applicable law), this will not be taken to be a formal waiver of Anduril's rights and that those -rights or remedies will still be available to Anduril. - - 14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of the License Agreement is invalid, then -that provision will be removed from the License Agreement without affecting the rest of the License Agreement. The remaining provisions -of the License Agreement will continue to be valid and enforceable. - - 14.4 You acknowledge and agree that any subsidiaries or affiliates of Anduril is the parent shall be third party beneficiaries to the License -Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of the License Agreement -that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to the -License Agreement. - - 14.5 EXPORT RESTRICTIONS. YOU MAY NOT EXPORT THIS LICENSE. THE SDK MAY BE SUBJECT TO UNITED STATES EXPORT -LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND -REGULATIONS THAT APPLY TO THE SDK. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END -USE. - - 14.6 The rights granted in the License Agreement may not be assigned or transferred by either you or Anduril without the prior written -approval of the other party. Neither you nor Anduril shall be permitted to delegate their responsibilities or obligations under the License -Agreement without the prior written approval of the other party. - - 14.7 The License Agreement, and your relationship with Anduril under the License Agreement, shall be governed by the laws of the State -of Delaware without regard to its conflict of laws provisions. Except for claims for injunctive or equitable relief, and claims regarding -intellectual property rights to the extent not relating to indemnification under this Agreement (all of which may be brought in any competent -state or federal court), any dispute arising under this Agreement shall be finally settled in accordance with the Comprehensive Arbitration -Rules of the Judicial Arbitration and Mediation Service, Inc. (“JAMS”) by three arbitrators appointed in accordance with such Rules. The -arbitration shall take place in Irvine, California and the arbitral decision may be enforced in any competent U.S. federal court. In the event -of any court action, you agree to submit to the exclusive jurisdiction of the courts located in the city of Irvine located in Orange, California. -Notwithstanding this, you agree that Anduril shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal -relief) in any jurisdiction. - -**April 14, 2025** \ No newline at end of file diff --git a/README.md b/README.md index b7a692a..da22b31 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ ![](https://www.anduril.com/lattice-sdk/) -[![fern shield](https://img.shields.io/badge/%F0%9F%8C%BF-Built%20with%20Fern-brightgreen)](https://buildwithfern.com?utm_source=github&utm_medium=github&utm_campaign=readme&utm_source=https%3A%2F%2Fgithub.com%2Fanduril%2Flattice-sdk-python) [![pypi](https://img.shields.io/pypi/v/anduril-lattice-sdk)](https://pypi.python.org/pypi/anduril-lattice-sdk) The Lattice SDK Python library provides convenient access to the Lattice SDK APIs from Python. @@ -29,7 +28,7 @@ For support with this library please reach out to your Anduril representative. ## Reference -A full reference for this library is available [here](https://github.com/anduril/lattice-sdk-python/blob/HEAD/./reference.md). +A full reference for this library is available [here](https://github.com/fern-api/lattice-sdk-python/blob/HEAD/./reference.md). ## Usage diff --git a/poetry.lock b/poetry.lock index 0985d99..fef3795 100644 --- a/poetry.lock +++ b/poetry.lock @@ -38,13 +38,13 @@ trio = ["trio (>=0.26.1)"] [[package]] name = "certifi" -version = "2025.8.3" +version = "2025.10.5" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" files = [ - {file = "certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5"}, - {file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"}, + {file = "certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de"}, + {file = "certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43"}, ] [[package]] @@ -131,26 +131,15 @@ http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] zstd = ["zstandard (>=0.18.0)"] -[[package]] -name = "httpx-sse" -version = "0.4.0" -description = "Consume Server-Sent Event (SSE) messages with HTTPX." -optional = false -python-versions = ">=3.8" -files = [ - {file = "httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721"}, - {file = "httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f"}, -] - [[package]] name = "idna" -version = "3.10" +version = "3.11" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, - {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, + {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, + {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, ] [package.extras] @@ -494,43 +483,53 @@ files = [ [[package]] name = "tomli" -version = "2.2.1" +version = "2.3.0" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, - {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, - {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, - {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, - {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, - {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, - {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, - {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, - {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, - {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, - {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, - {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, - {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, - {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, + {file = "tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45"}, + {file = "tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba"}, + {file = "tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf"}, + {file = "tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441"}, + {file = "tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845"}, + {file = "tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c"}, + {file = "tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456"}, + {file = "tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be"}, + {file = "tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac"}, + {file = "tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22"}, + {file = "tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f"}, + {file = "tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52"}, + {file = "tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8"}, + {file = "tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6"}, + {file = "tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876"}, + {file = "tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878"}, + {file = "tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b"}, + {file = "tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae"}, + {file = "tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b"}, + {file = "tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf"}, + {file = "tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f"}, + {file = "tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05"}, + {file = "tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606"}, + {file = "tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999"}, + {file = "tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e"}, + {file = "tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3"}, + {file = "tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc"}, + {file = "tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0"}, + {file = "tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879"}, + {file = "tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005"}, + {file = "tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463"}, + {file = "tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8"}, + {file = "tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77"}, + {file = "tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf"}, + {file = "tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530"}, + {file = "tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b"}, + {file = "tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67"}, + {file = "tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f"}, + {file = "tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0"}, + {file = "tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba"}, + {file = "tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b"}, + {file = "tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549"}, ] [[package]] @@ -558,4 +557,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "3c4bf0b75d27d2ce3738ca3d6b64dfb03909c56fb8e280a98890abd4619134d8" +content-hash = "8551b871abee465e23fb0966d51f2c155fd257b55bdcb0c02d095de19f92f358" diff --git a/pyproject.toml b/pyproject.toml index 68c4a4b..fe2dd10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,16 +3,11 @@ name = "anduril-lattice-sdk" [tool.poetry] name = "anduril-lattice-sdk" -version = "2.3.0" -description = "HTTP clients for the Anduril Lattice SDK" +version = "0.0.1" +description = "" readme = "README.md" -authors = [ - "Anduril Industries " -] -keywords = [ - "anduril", - "lattice" -] +authors = [] +keywords = [] classifiers = [ "Intended Audience :: Developers", @@ -35,15 +30,12 @@ packages = [ { include = "anduril", from = "src"} ] -[project.urls] -Documentation = 'https://developer.anduril.com' -Homepage = 'https://www.anduril.com/lattice-sdk/' -Repository = 'https://github.com/anduril/lattice-sdk-python' +[tool.poetry.urls] +Repository = 'https://github.com/fern-api/lattice-sdk-python' [tool.poetry.dependencies] python = "^3.8" httpx = ">=0.21.2" -httpx-sse = "0.4.0" pydantic = ">= 1.9.2" pydantic-core = ">=2.18.2" typing_extensions = ">= 4.0.0" diff --git a/requirements.txt b/requirements.txt index f129cb3..e80f640 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ httpx>=0.21.2 -httpx-sse==0.4.0 pydantic>= 1.9.2 pydantic-core>=2.18.2 typing_extensions>= 4.0.0 diff --git a/src/anduril/core/client_wrapper.py b/src/anduril/core/client_wrapper.py index b258a72..91f8171 100644 --- a/src/anduril/core/client_wrapper.py +++ b/src/anduril/core/client_wrapper.py @@ -22,10 +22,9 @@ def __init__( def get_headers(self) -> typing.Dict[str, str]: headers: typing.Dict[str, str] = { - "User-Agent": "anduril-lattice-sdk/2.3.0", "X-Fern-Language": "Python", "X-Fern-SDK-Name": "anduril-lattice-sdk", - "X-Fern-SDK-Version": "2.3.0", + "X-Fern-SDK-Version": "0.0.1", **(self.get_custom_headers() or {}), } token = self._get_token() diff --git a/src/anduril/core/http_sse/__init__.py b/src/anduril/core/http_sse/__init__.py new file mode 100644 index 0000000..730e5a3 --- /dev/null +++ b/src/anduril/core/http_sse/__init__.py @@ -0,0 +1,42 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from ._api import EventSource, aconnect_sse, connect_sse + from ._exceptions import SSEError + from ._models import ServerSentEvent +_dynamic_imports: typing.Dict[str, str] = { + "EventSource": "._api", + "SSEError": "._exceptions", + "ServerSentEvent": "._models", + "aconnect_sse": "._api", + "connect_sse": "._api", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["EventSource", "SSEError", "ServerSentEvent", "aconnect_sse", "connect_sse"] diff --git a/src/anduril/core/http_sse/_api.py b/src/anduril/core/http_sse/_api.py new file mode 100644 index 0000000..f900b3b --- /dev/null +++ b/src/anduril/core/http_sse/_api.py @@ -0,0 +1,112 @@ +# This file was auto-generated by Fern from our API Definition. + +import re +from contextlib import asynccontextmanager, contextmanager +from typing import Any, AsyncGenerator, AsyncIterator, Iterator, cast + +import httpx +from ._decoders import SSEDecoder +from ._exceptions import SSEError +from ._models import ServerSentEvent + + +class EventSource: + def __init__(self, response: httpx.Response) -> None: + self._response = response + + def _check_content_type(self) -> None: + content_type = self._response.headers.get("content-type", "").partition(";")[0] + if "text/event-stream" not in content_type: + raise SSEError( + f"Expected response header Content-Type to contain 'text/event-stream', got {content_type!r}" + ) + + def _get_charset(self) -> str: + """Extract charset from Content-Type header, fallback to UTF-8.""" + content_type = self._response.headers.get("content-type", "") + + # Parse charset parameter using regex + charset_match = re.search(r"charset=([^;\s]+)", content_type, re.IGNORECASE) + if charset_match: + charset = charset_match.group(1).strip("\"'") + # Validate that it's a known encoding + try: + # Test if the charset is valid by trying to encode/decode + "test".encode(charset).decode(charset) + return charset + except (LookupError, UnicodeError): + # If charset is invalid, fall back to UTF-8 + pass + + # Default to UTF-8 if no charset specified or invalid charset + return "utf-8" + + @property + def response(self) -> httpx.Response: + return self._response + + def iter_sse(self) -> Iterator[ServerSentEvent]: + self._check_content_type() + decoder = SSEDecoder() + charset = self._get_charset() + + buffer = "" + for chunk in self._response.iter_bytes(): + # Decode chunk using detected charset + text_chunk = chunk.decode(charset, errors="replace") + buffer += text_chunk + + # Process complete lines + while "\n" in buffer: + line, buffer = buffer.split("\n", 1) + line = line.rstrip("\r") + sse = decoder.decode(line) + # when we reach a "\n\n" => line = '' + # => decoder will attempt to return an SSE Event + if sse is not None: + yield sse + + # Process any remaining data in buffer + if buffer.strip(): + line = buffer.rstrip("\r") + sse = decoder.decode(line) + if sse is not None: + yield sse + + async def aiter_sse(self) -> AsyncGenerator[ServerSentEvent, None]: + self._check_content_type() + decoder = SSEDecoder() + lines = cast(AsyncGenerator[str, None], self._response.aiter_lines()) + try: + async for line in lines: + line = line.rstrip("\n") + sse = decoder.decode(line) + if sse is not None: + yield sse + finally: + await lines.aclose() + + +@contextmanager +def connect_sse(client: httpx.Client, method: str, url: str, **kwargs: Any) -> Iterator[EventSource]: + headers = kwargs.pop("headers", {}) + headers["Accept"] = "text/event-stream" + headers["Cache-Control"] = "no-store" + + with client.stream(method, url, headers=headers, **kwargs) as response: + yield EventSource(response) + + +@asynccontextmanager +async def aconnect_sse( + client: httpx.AsyncClient, + method: str, + url: str, + **kwargs: Any, +) -> AsyncIterator[EventSource]: + headers = kwargs.pop("headers", {}) + headers["Accept"] = "text/event-stream" + headers["Cache-Control"] = "no-store" + + async with client.stream(method, url, headers=headers, **kwargs) as response: + yield EventSource(response) diff --git a/src/anduril/core/http_sse/_decoders.py b/src/anduril/core/http_sse/_decoders.py new file mode 100644 index 0000000..339b089 --- /dev/null +++ b/src/anduril/core/http_sse/_decoders.py @@ -0,0 +1,61 @@ +# This file was auto-generated by Fern from our API Definition. + +from typing import List, Optional + +from ._models import ServerSentEvent + + +class SSEDecoder: + def __init__(self) -> None: + self._event = "" + self._data: List[str] = [] + self._last_event_id = "" + self._retry: Optional[int] = None + + def decode(self, line: str) -> Optional[ServerSentEvent]: + # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501 + + if not line: + if not self._event and not self._data and not self._last_event_id and self._retry is None: + return None + + sse = ServerSentEvent( + event=self._event, + data="\n".join(self._data), + id=self._last_event_id, + retry=self._retry, + ) + + # NOTE: as per the SSE spec, do not reset last_event_id. + self._event = "" + self._data = [] + self._retry = None + + return sse + + if line.startswith(":"): + return None + + fieldname, _, value = line.partition(":") + + if value.startswith(" "): + value = value[1:] + + if fieldname == "event": + self._event = value + elif fieldname == "data": + self._data.append(value) + elif fieldname == "id": + if "\0" in value: + pass + else: + self._last_event_id = value + elif fieldname == "retry": + try: + self._retry = int(value) + except (TypeError, ValueError): + pass + else: + pass # Field is ignored. + + return None diff --git a/src/anduril/core/http_sse/_exceptions.py b/src/anduril/core/http_sse/_exceptions.py new file mode 100644 index 0000000..81605a8 --- /dev/null +++ b/src/anduril/core/http_sse/_exceptions.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import httpx + + +class SSEError(httpx.TransportError): + pass diff --git a/src/anduril/core/http_sse/_models.py b/src/anduril/core/http_sse/_models.py new file mode 100644 index 0000000..1af57f8 --- /dev/null +++ b/src/anduril/core/http_sse/_models.py @@ -0,0 +1,17 @@ +# This file was auto-generated by Fern from our API Definition. + +import json +from dataclasses import dataclass +from typing import Any, Optional + + +@dataclass(frozen=True) +class ServerSentEvent: + event: str = "message" + data: str = "" + id: str = "" + retry: Optional[int] = None + + def json(self) -> Any: + """Parse the data field as JSON.""" + return json.loads(self.data) diff --git a/src/anduril/core/pydantic_utilities.py b/src/anduril/core/pydantic_utilities.py index 8906cdf..185e5c4 100644 --- a/src/anduril/core/pydantic_utilities.py +++ b/src/anduril/core/pydantic_utilities.py @@ -220,7 +220,9 @@ def universal_root_validator( ) -> Callable[[AnyCallable], AnyCallable]: def decorator(func: AnyCallable) -> AnyCallable: if IS_PYDANTIC_V2: - return cast(AnyCallable, pydantic.model_validator(mode="before" if pre else "after")(func)) # type: ignore[attr-defined] + # In Pydantic v2, for RootModel we always use "before" mode + # The custom validators transform the input value before the model is created + return cast(AnyCallable, pydantic.model_validator(mode="before")(func)) # type: ignore[attr-defined] return cast(AnyCallable, pydantic.root_validator(pre=pre)(func)) # type: ignore[call-overload] return decorator diff --git a/src/anduril/entities/raw_client.py b/src/anduril/entities/raw_client.py index 3cce608..cfdb30e 100644 --- a/src/anduril/entities/raw_client.py +++ b/src/anduril/entities/raw_client.py @@ -2,14 +2,14 @@ import contextlib import datetime as dt -import json import typing from json.decoder import JSONDecodeError +from logging import error, warning -import httpx_sse from ..core.api_error import ApiError from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.http_sse._api import EventSource from ..core.jsonable_encoder import jsonable_encoder from ..core.pydantic_utilities import parse_obj_as from ..core.request_options import RequestOptions @@ -814,7 +814,7 @@ def _stream() -> HttpResponse[typing.Iterator[StreamEntitiesResponse]]: if 200 <= _response.status_code < 300: def _iter(): - _event_source = httpx_sse.EventSource(_response) + _event_source = EventSource(_response) for _sse in _event_source.iter_sse(): if _sse.data == None: return @@ -823,11 +823,19 @@ def _iter(): StreamEntitiesResponse, parse_obj_as( type_=StreamEntitiesResponse, # type: ignore - object_=json.loads(_sse.data), + object_=_sse.json(), ), ) - except Exception: - pass + except JSONDecodeError as e: + warning(f"Skipping SSE event with invalid JSON: {e}, sse: {_sse!r}") + except (TypeError, ValueError, KeyError, AttributeError) as e: + warning( + f"Skipping SSE event due to model construction error: {type(e).__name__}: {e}, sse: {_sse!r}" + ) + except Exception as e: + error( + f"Unexpected error processing SSE event: {type(e).__name__}: {e}, sse: {_sse!r}" + ) return return HttpResponse(response=_response, data=_iter()) @@ -1619,7 +1627,7 @@ async def _stream() -> AsyncHttpResponse[typing.AsyncIterator[StreamEntitiesResp if 200 <= _response.status_code < 300: async def _iter(): - _event_source = httpx_sse.EventSource(_response) + _event_source = EventSource(_response) async for _sse in _event_source.aiter_sse(): if _sse.data == None: return @@ -1628,11 +1636,19 @@ async def _iter(): StreamEntitiesResponse, parse_obj_as( type_=StreamEntitiesResponse, # type: ignore - object_=json.loads(_sse.data), + object_=_sse.json(), ), ) - except Exception: - pass + except JSONDecodeError as e: + warning(f"Skipping SSE event with invalid JSON: {e}, sse: {_sse!r}") + except (TypeError, ValueError, KeyError, AttributeError) as e: + warning( + f"Skipping SSE event due to model construction error: {type(e).__name__}: {e}, sse: {_sse!r}" + ) + except Exception as e: + error( + f"Unexpected error processing SSE event: {type(e).__name__}: {e}, sse: {_sse!r}" + ) return return AsyncHttpResponse(response=_response, data=_iter()) diff --git a/src/anduril/entities/types/stream_entities_response.py b/src/anduril/entities/types/stream_entities_response.py index 068e8e0..f7ceb7d 100644 --- a/src/anduril/entities/types/stream_entities_response.py +++ b/src/anduril/entities/types/stream_entities_response.py @@ -52,9 +52,9 @@ class Config: extra = pydantic.Extra.allow -from ...types.entity import Entity # noqa: E402, F401, I001 -from ...types.override import Override # noqa: E402, F401, I001 -from ...types.overrides import Overrides # noqa: E402, F401, I001 +from ...types.entity import Entity # noqa: E402, I001 -StreamEntitiesResponse = typing.Union[StreamEntitiesResponse_Heartbeat, StreamEntitiesResponse_Entity] +StreamEntitiesResponse = typing_extensions.Annotated[ + typing.Union[StreamEntitiesResponse_Heartbeat, StreamEntitiesResponse_Entity], pydantic.Field(discriminator="event") +] update_forward_refs(StreamEntitiesResponse_Entity) diff --git a/src/anduril/types/agent_request.py b/src/anduril/types/agent_request.py index 7dd56fa..768679d 100644 --- a/src/anduril/types/agent_request.py +++ b/src/anduril/types/agent_request.py @@ -34,9 +34,4 @@ class Config: extra = pydantic.Extra.allow -from .entity import Entity # noqa: E402, F401, I001 -from .override import Override # noqa: E402, F401, I001 -from .overrides import Overrides # noqa: E402, F401, I001 -from .principal import Principal # noqa: E402, F401, I001 - update_forward_refs(AgentRequest) diff --git a/src/anduril/types/cancel_request.py b/src/anduril/types/cancel_request.py index d791c00..381a072 100644 --- a/src/anduril/types/cancel_request.py +++ b/src/anduril/types/cancel_request.py @@ -38,6 +38,6 @@ class Config: extra = pydantic.Extra.allow -from .principal import Principal # noqa: E402, F401, I001 +from .principal import Principal # noqa: E402, I001 update_forward_refs(CancelRequest) diff --git a/src/anduril/types/entity.py b/src/anduril/types/entity.py index 22ae604..5532c9f 100644 --- a/src/anduril/types/entity.py +++ b/src/anduril/types/entity.py @@ -300,7 +300,6 @@ class Config: extra = pydantic.Extra.allow -from .override import Override # noqa: E402, F401, I001 -from .overrides import Overrides # noqa: E402, F401, I001 +from .overrides import Overrides # noqa: E402, I001 update_forward_refs(Entity) diff --git a/src/anduril/types/entity_event.py b/src/anduril/types/entity_event.py index 12a056b..cf8f5e3 100644 --- a/src/anduril/types/entity_event.py +++ b/src/anduril/types/entity_event.py @@ -33,8 +33,6 @@ class Config: extra = pydantic.Extra.allow -from .entity import Entity # noqa: E402, F401, I001 -from .override import Override # noqa: E402, F401, I001 -from .overrides import Overrides # noqa: E402, F401, I001 +from .entity import Entity # noqa: E402, I001 update_forward_refs(EntityEvent) diff --git a/src/anduril/types/entity_event_response.py b/src/anduril/types/entity_event_response.py index cac24a1..bb78dc3 100644 --- a/src/anduril/types/entity_event_response.py +++ b/src/anduril/types/entity_event_response.py @@ -33,8 +33,4 @@ class Config: extra = pydantic.Extra.allow -from .entity import Entity # noqa: E402, F401, I001 -from .override import Override # noqa: E402, F401, I001 -from .overrides import Overrides # noqa: E402, F401, I001 - update_forward_refs(EntityEventResponse) diff --git a/src/anduril/types/entity_stream_event.py b/src/anduril/types/entity_stream_event.py index 59ff689..c7aea71 100644 --- a/src/anduril/types/entity_stream_event.py +++ b/src/anduril/types/entity_stream_event.py @@ -18,8 +18,3 @@ class Config: frozen = True smart_union = True extra = pydantic.Extra.allow - - -from .entity import Entity # noqa: E402, F401, I001 -from .override import Override # noqa: E402, F401, I001 -from .overrides import Overrides # noqa: E402, F401, I001 diff --git a/src/anduril/types/execute_request.py b/src/anduril/types/execute_request.py index e59edda..568745f 100644 --- a/src/anduril/types/execute_request.py +++ b/src/anduril/types/execute_request.py @@ -29,9 +29,4 @@ class Config: extra = pydantic.Extra.allow -from .entity import Entity # noqa: E402, F401, I001 -from .override import Override # noqa: E402, F401, I001 -from .overrides import Overrides # noqa: E402, F401, I001 -from .principal import Principal # noqa: E402, F401, I001 - update_forward_refs(ExecuteRequest) diff --git a/src/anduril/types/override.py b/src/anduril/types/override.py index 465da95..7cf10fb 100644 --- a/src/anduril/types/override.py +++ b/src/anduril/types/override.py @@ -71,7 +71,6 @@ class Config: extra = pydantic.Extra.allow -from .entity import Entity # noqa: E402, F401, I001 -from .overrides import Overrides # noqa: E402, F401, I001 +from .entity import Entity # noqa: E402, I001 update_forward_refs(Override) diff --git a/src/anduril/types/overrides.py b/src/anduril/types/overrides.py index 477eeaf..496b404 100644 --- a/src/anduril/types/overrides.py +++ b/src/anduril/types/overrides.py @@ -25,7 +25,6 @@ class Config: extra = pydantic.Extra.allow -from .entity import Entity # noqa: E402, F401, I001 -from .override import Override # noqa: E402, F401, I001 +from .override import Override # noqa: E402, I001 update_forward_refs(Overrides) diff --git a/src/anduril/types/pose.py b/src/anduril/types/pose.py index 54e2d7d..a99d3b7 100644 --- a/src/anduril/types/pose.py +++ b/src/anduril/types/pose.py @@ -30,9 +30,9 @@ class Pose(UniversalBaseModel): Implementations of this quaternion should left multiply this quaternion to transform a point from the Pose frame to the enu frame. - Point posePt{1,0,0}; - Rotation attPoseToEnu{}; - Point = attPoseToEnu*posePt; + Point posePt{1,0,0}; + Rotation attPoseToEnu{}; + Point = attPoseToEnu*posePt; This transformed point represents some vector in ENU space that is aligned with the x axis of the attPoseToEnu matrix. diff --git a/src/anduril/types/relations.py b/src/anduril/types/relations.py index 664062a..dbb995e 100644 --- a/src/anduril/types/relations.py +++ b/src/anduril/types/relations.py @@ -37,6 +37,6 @@ class Config: extra = pydantic.Extra.allow -from .principal import Principal # noqa: E402, F401, I001 +from .principal import Principal # noqa: E402, I001 update_forward_refs(Relations) diff --git a/src/anduril/types/status.py b/src/anduril/types/status.py index 0d92329..671df1e 100644 --- a/src/anduril/types/status.py +++ b/src/anduril/types/status.py @@ -3,28 +3,27 @@ import typing import pydantic +import typing_extensions from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .google_protobuf_any import GoogleProtobufAny +from ..core.serialization import FieldMetadata class Status(UniversalBaseModel): """ - The `Status` type defines a logical error model that is suitable for different programming environments, including REST APIs and RPC APIs. It is used by [gRPC](https://github.com/grpc). Each `Status` message contains three pieces of data: error code, error message, and error details. You can find out more about this error model and how to work with it in the [API Design Guide](https://cloud.google.com/apis/design/errors). + Contains status of entities. """ - code: typing.Optional[int] = pydantic.Field(default=None) + platform_activity: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="platformActivity")] = ( + pydantic.Field(default=None) + ) """ - The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + A string that describes the activity that the entity is performing. + Examples include "RECONNAISSANCE", "INTERDICTION", "RETURN TO BASE (RTB)", "PREPARING FOR LAUNCH". """ - message: typing.Optional[str] = pydantic.Field(default=None) + role: typing.Optional[str] = pydantic.Field(default=None) """ - A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. - """ - - details: typing.Optional[typing.List[GoogleProtobufAny]] = pydantic.Field(default=None) - """ - A list of messages that carry the error details. There is a common set of message types for APIs to use. + A human-readable string that describes the role the entity is currently performing. E.g. "Team Member", "Commander". """ if IS_PYDANTIC_V2: diff --git a/src/anduril/types/task.py b/src/anduril/types/task.py index ced2b89..bdc4693 100644 --- a/src/anduril/types/task.py +++ b/src/anduril/types/task.py @@ -129,9 +129,6 @@ class Config: extra = pydantic.Extra.allow -from .principal import Principal # noqa: E402, F401, I001 -from .entity import Entity # noqa: E402, F401, I001 -from .override import Override # noqa: E402, F401, I001 -from .overrides import Overrides # noqa: E402, F401, I001 +from .principal import Principal # noqa: E402, I001 update_forward_refs(Task) diff --git a/src/anduril/types/task_entity.py b/src/anduril/types/task_entity.py index 6b2c42a..ea4ac78 100644 --- a/src/anduril/types/task_entity.py +++ b/src/anduril/types/task_entity.py @@ -33,8 +33,6 @@ class Config: extra = pydantic.Extra.allow -from .entity import Entity # noqa: E402, F401, I001 -from .override import Override # noqa: E402, F401, I001 -from .overrides import Overrides # noqa: E402, F401, I001 +from .entity import Entity # noqa: E402, I001 update_forward_refs(TaskEntity) diff --git a/src/anduril/types/task_query_results.py b/src/anduril/types/task_query_results.py index 496ac80..7ca8758 100644 --- a/src/anduril/types/task_query_results.py +++ b/src/anduril/types/task_query_results.py @@ -33,9 +33,4 @@ class Config: extra = pydantic.Extra.allow -from .entity import Entity # noqa: E402, F401, I001 -from .override import Override # noqa: E402, F401, I001 -from .overrides import Overrides # noqa: E402, F401, I001 -from .principal import Principal # noqa: E402, F401, I001 - update_forward_refs(TaskQueryResults)