@planqk/planqk-api-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.devcontainer/devcontainer.json +32 -0
- package/.devcontainer/post-create.sh +7 -0
- package/.env.template +2 -0
- package/.gitlab-ci.yml +71 -0
- package/.python-version +1 -0
- package/.releaserc.json +45 -0
- package/LICENSE +201 -0
- package/README-node.md +18 -0
- package/README-python.md +21 -0
- package/README.md +56 -0
- package/dist/Client.d.ts +32 -0
- package/dist/Client.js +60 -0
- package/dist/api/errors/BadRequestError.d.ts +8 -0
- package/dist/api/errors/BadRequestError.js +52 -0
- package/dist/api/errors/ForbiddenError.d.ts +8 -0
- package/dist/api/errors/ForbiddenError.js +52 -0
- package/dist/api/errors/InternalServerError.d.ts +8 -0
- package/dist/api/errors/InternalServerError.js +52 -0
- package/dist/api/errors/NotFoundError.d.ts +8 -0
- package/dist/api/errors/NotFoundError.js +52 -0
- package/dist/api/errors/UnauthorizedError.d.ts +8 -0
- package/dist/api/errors/UnauthorizedError.js +52 -0
- package/dist/api/errors/index.d.ts +5 -0
- package/dist/api/errors/index.js +21 -0
- package/dist/api/index.d.ts +3 -0
- package/dist/api/index.js +19 -0
- package/dist/api/resources/dataPools/client/Client.d.ts +177 -0
- package/dist/api/resources/dataPools/client/Client.js +676 -0
- package/dist/api/resources/dataPools/client/index.d.ts +2 -0
- package/dist/api/resources/dataPools/client/index.js +17 -0
- package/dist/api/resources/dataPools/client/requests/AddDataPoolFileRequest.d.ts +14 -0
- package/dist/api/resources/dataPools/client/requests/AddDataPoolFileRequest.js +5 -0
- package/dist/api/resources/dataPools/client/requests/CreateDataPoolRequest.d.ts +10 -0
- package/dist/api/resources/dataPools/client/requests/CreateDataPoolRequest.js +5 -0
- package/dist/api/resources/dataPools/client/requests/UpdateDataPoolRequest.d.ts +12 -0
- package/dist/api/resources/dataPools/client/requests/UpdateDataPoolRequest.js +5 -0
- package/dist/api/resources/dataPools/client/requests/index.d.ts +3 -0
- package/dist/api/resources/dataPools/client/requests/index.js +2 -0
- package/dist/api/resources/dataPools/index.d.ts +1 -0
- package/dist/api/resources/dataPools/index.js +17 -0
- package/dist/api/resources/index.d.ts +2 -0
- package/dist/api/resources/index.js +41 -0
- package/dist/api/types/DataPoolDto.d.ts +23 -0
- package/dist/api/types/DataPoolDto.js +14 -0
- package/dist/api/types/DataPoolFileDto.d.ts +12 -0
- package/dist/api/types/DataPoolFileDto.js +5 -0
- package/dist/api/types/OauthScope.d.ts +9 -0
- package/dist/api/types/OauthScope.js +9 -0
- package/dist/api/types/index.d.ts +3 -0
- package/dist/api/types/index.js +19 -0
- package/dist/core/fetcher/APIResponse.d.ts +20 -0
- package/dist/core/fetcher/APIResponse.js +2 -0
- package/dist/core/fetcher/BinaryResponse.d.ts +20 -0
- package/dist/core/fetcher/BinaryResponse.js +17 -0
- package/dist/core/fetcher/Fetcher.d.ts +40 -0
- package/dist/core/fetcher/Fetcher.js +105 -0
- package/dist/core/fetcher/Headers.d.ts +2 -0
- package/dist/core/fetcher/Headers.js +85 -0
- package/dist/core/fetcher/HttpResponsePromise.d.ts +58 -0
- package/dist/core/fetcher/HttpResponsePromise.js +94 -0
- package/dist/core/fetcher/RawResponse.d.ts +29 -0
- package/dist/core/fetcher/RawResponse.js +44 -0
- package/dist/core/fetcher/ResponseWithBody.d.ts +4 -0
- package/dist/core/fetcher/ResponseWithBody.js +6 -0
- package/dist/core/fetcher/Supplier.d.ts +4 -0
- package/dist/core/fetcher/Supplier.js +13 -0
- package/dist/core/fetcher/createRequestUrl.d.ts +1 -0
- package/dist/core/fetcher/createRequestUrl.js +8 -0
- package/dist/core/fetcher/getErrorResponseBody.d.ts +1 -0
- package/dist/core/fetcher/getErrorResponseBody.js +32 -0
- package/dist/core/fetcher/getFetchFn.d.ts +1 -0
- package/dist/core/fetcher/getFetchFn.js +6 -0
- package/dist/core/fetcher/getHeader.d.ts +1 -0
- package/dist/core/fetcher/getHeader.js +11 -0
- package/dist/core/fetcher/getRequestBody.d.ts +7 -0
- package/dist/core/fetcher/getRequestBody.js +12 -0
- package/dist/core/fetcher/getResponseBody.d.ts +1 -0
- package/dist/core/fetcher/getResponseBody.js +44 -0
- package/dist/core/fetcher/index.d.ts +9 -0
- package/dist/core/fetcher/index.js +15 -0
- package/dist/core/fetcher/makeRequest.d.ts +1 -0
- package/dist/core/fetcher/makeRequest.js +33 -0
- package/dist/core/fetcher/requestWithRetries.d.ts +1 -0
- package/dist/core/fetcher/requestWithRetries.js +29 -0
- package/dist/core/fetcher/signals.d.ts +11 -0
- package/dist/core/fetcher/signals.js +36 -0
- package/dist/core/file.d.ts +1 -0
- package/dist/core/file.js +2 -0
- package/dist/core/form-data-utils/FormDataWrapper.d.ts +16 -0
- package/dist/core/form-data-utils/FormDataWrapper.js +166 -0
- package/dist/core/form-data-utils/encodeAsFormParameter.d.ts +1 -0
- package/dist/core/form-data-utils/encodeAsFormParameter.js +12 -0
- package/dist/core/form-data-utils/index.d.ts +2 -0
- package/dist/core/form-data-utils/index.js +20 -0
- package/dist/core/headers.d.ts +3 -0
- package/dist/core/headers.js +29 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +44 -0
- package/dist/core/json.d.ts +15 -0
- package/dist/core/json.js +24 -0
- package/dist/core/runtime/index.d.ts +1 -0
- package/dist/core/runtime/index.js +5 -0
- package/dist/core/runtime/runtime.d.ts +9 -0
- package/dist/core/runtime/runtime.js +101 -0
- package/dist/core/url/index.d.ts +2 -0
- package/dist/core/url/index.js +7 -0
- package/dist/core/url/join.d.ts +1 -0
- package/dist/core/url/join.js +49 -0
- package/dist/core/url/qs.d.ts +6 -0
- package/dist/core/url/qs.js +67 -0
- package/dist/environments.d.ts +7 -0
- package/dist/environments.js +9 -0
- package/dist/errors/PlanqkApiError.d.ts +15 -0
- package/dist/errors/PlanqkApiError.js +33 -0
- package/dist/errors/PlanqkApiTimeoutError.d.ts +6 -0
- package/dist/errors/PlanqkApiTimeoutError.js +13 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.js +7 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +44 -0
- package/eslint.config.mjs +11 -0
- package/fern/fern.config.json +4 -0
- package/fern/generators.yml +25 -0
- package/fern/openapi/openapi.json +610 -0
- package/notebooks/python-sdk.ipynb +218 -0
- package/package.json +48 -0
- package/planqk/__init__.py +0 -0
- package/planqk/api/__init__.py +1 -0
- package/planqk/api/_version.py +1 -0
- package/planqk/api/client.py +19 -0
- package/planqk/api/credentials.py +103 -0
- package/planqk/api/sdk/__init__.py +25 -0
- package/planqk/api/sdk/client.py +153 -0
- package/planqk/api/sdk/core/__init__.py +52 -0
- package/planqk/api/sdk/core/api_error.py +23 -0
- package/planqk/api/sdk/core/client_wrapper.py +76 -0
- package/planqk/api/sdk/core/datetime_utils.py +28 -0
- package/planqk/api/sdk/core/file.py +67 -0
- package/planqk/api/sdk/core/force_multipart.py +16 -0
- package/planqk/api/sdk/core/http_client.py +543 -0
- package/planqk/api/sdk/core/http_response.py +55 -0
- package/planqk/api/sdk/core/jsonable_encoder.py +100 -0
- package/planqk/api/sdk/core/pydantic_utilities.py +255 -0
- package/planqk/api/sdk/core/query_encoder.py +58 -0
- package/planqk/api/sdk/core/remove_none_from_dict.py +11 -0
- package/planqk/api/sdk/core/request_options.py +35 -0
- package/planqk/api/sdk/core/serialization.py +276 -0
- package/planqk/api/sdk/data_pools/__init__.py +4 -0
- package/planqk/api/sdk/data_pools/client.py +700 -0
- package/planqk/api/sdk/data_pools/raw_client.py +1650 -0
- package/planqk/api/sdk/environment.py +7 -0
- package/planqk/api/sdk/errors/__init__.py +11 -0
- package/planqk/api/sdk/errors/bad_request_error.py +10 -0
- package/planqk/api/sdk/errors/forbidden_error.py +10 -0
- package/planqk/api/sdk/errors/internal_server_error.py +10 -0
- package/planqk/api/sdk/errors/not_found_error.py +10 -0
- package/planqk/api/sdk/errors/unauthorized_error.py +10 -0
- package/planqk/api/sdk/types/__init__.py +10 -0
- package/planqk/api/sdk/types/data_pool_dto.py +33 -0
- package/planqk/api/sdk/types/data_pool_dto_current_user_permission.py +5 -0
- package/planqk/api/sdk/types/data_pool_file_dto.py +27 -0
- package/planqk/api/sdk/types/oauth_scope.py +5 -0
- package/pyproject.toml +51 -0
- package/scripts/update-version.sh +6 -0
- package/src/Client.ts +53 -0
- package/src/api/errors/BadRequestError.ts +18 -0
- package/src/api/errors/ForbiddenError.ts +18 -0
- package/src/api/errors/InternalServerError.ts +18 -0
- package/src/api/errors/NotFoundError.ts +18 -0
- package/src/api/errors/UnauthorizedError.ts +18 -0
- package/src/api/errors/index.ts +5 -0
- package/src/api/index.ts +3 -0
- package/src/api/resources/dataPools/client/Client.ts +825 -0
- package/src/api/resources/dataPools/client/index.ts +2 -0
- package/src/api/resources/dataPools/client/requests/AddDataPoolFileRequest.ts +17 -0
- package/src/api/resources/dataPools/client/requests/CreateDataPoolRequest.ts +11 -0
- package/src/api/resources/dataPools/client/requests/UpdateDataPoolRequest.ts +13 -0
- package/src/api/resources/dataPools/client/requests/index.ts +3 -0
- package/src/api/resources/dataPools/index.ts +1 -0
- package/src/api/resources/index.ts +2 -0
- package/src/api/types/DataPoolDto.ts +25 -0
- package/src/api/types/DataPoolFileDto.ts +13 -0
- package/src/api/types/OauthScope.ts +10 -0
- package/src/api/types/index.ts +3 -0
- package/src/core/fetcher/APIResponse.ts +23 -0
- package/src/core/fetcher/BinaryResponse.ts +36 -0
- package/src/core/fetcher/Fetcher.ts +163 -0
- package/src/core/fetcher/Headers.ts +93 -0
- package/src/core/fetcher/HttpResponsePromise.ts +116 -0
- package/src/core/fetcher/RawResponse.ts +61 -0
- package/src/core/fetcher/ResponseWithBody.ts +7 -0
- package/src/core/fetcher/Supplier.ts +11 -0
- package/src/core/fetcher/createRequestUrl.ts +6 -0
- package/src/core/fetcher/getErrorResponseBody.ts +32 -0
- package/src/core/fetcher/getFetchFn.ts +3 -0
- package/src/core/fetcher/getHeader.ts +8 -0
- package/src/core/fetcher/getRequestBody.ts +16 -0
- package/src/core/fetcher/getResponseBody.ts +43 -0
- package/src/core/fetcher/index.ts +9 -0
- package/src/core/fetcher/makeRequest.ts +44 -0
- package/src/core/fetcher/requestWithRetries.ts +33 -0
- package/src/core/fetcher/signals.ts +38 -0
- package/src/core/file.ts +11 -0
- package/src/core/form-data-utils/FormDataWrapper.ts +176 -0
- package/src/core/form-data-utils/encodeAsFormParameter.ts +12 -0
- package/src/core/form-data-utils/index.ts +2 -0
- package/src/core/headers.ts +35 -0
- package/src/core/index.ts +5 -0
- package/src/core/json.ts +27 -0
- package/src/core/runtime/index.ts +1 -0
- package/src/core/runtime/runtime.ts +133 -0
- package/src/core/url/index.ts +2 -0
- package/src/core/url/join.ts +55 -0
- package/src/core/url/qs.ts +74 -0
- package/src/environments.ts +9 -0
- package/src/errors/PlanqkApiError.ts +55 -0
- package/src/errors/PlanqkApiTimeoutError.ts +10 -0
- package/src/errors/index.ts +2 -0
- package/src/index.test.ts +17 -0
- package/src/index.ts +4 -0
- package/tsconfig.json +18 -0
- package/uv.lock +1102 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "markdown",
|
|
5
|
+
"metadata": {},
|
|
6
|
+
"source": [
|
|
7
|
+
"# Python SDK"
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"cell_type": "code",
|
|
12
|
+
"execution_count": null,
|
|
13
|
+
"metadata": {
|
|
14
|
+
"jupyter": {
|
|
15
|
+
"is_executing": true
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"outputs": [],
|
|
19
|
+
"source": [
|
|
20
|
+
"import os\n",
|
|
21
|
+
"\n",
|
|
22
|
+
"from dotenv import load_dotenv\n",
|
|
23
|
+
"\n",
|
|
24
|
+
"# Make a copy of .env.example and rename it to .env, place it in the\n",
|
|
25
|
+
"# root directory, and fill in the values.\n",
|
|
26
|
+
"\n",
|
|
27
|
+
"load_dotenv(override=True)\n",
|
|
28
|
+
"\n",
|
|
29
|
+
"access_token = os.getenv(\"PLANQK_PERSONAL_ACCESS_TOKEN\", None)"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"cell_type": "markdown",
|
|
34
|
+
"metadata": {},
|
|
35
|
+
"source": [
|
|
36
|
+
"## Usage"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"cell_type": "markdown",
|
|
41
|
+
"metadata": {},
|
|
42
|
+
"source": [
|
|
43
|
+
"### Data Pools"
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"cell_type": "code",
|
|
48
|
+
"execution_count": null,
|
|
49
|
+
"metadata": {},
|
|
50
|
+
"outputs": [],
|
|
51
|
+
"source": [
|
|
52
|
+
"from planqk.api.client import PlanqkApiClient\n",
|
|
53
|
+
"\n",
|
|
54
|
+
"client = PlanqkApiClient(access_token=access_token)\n",
|
|
55
|
+
"\n",
|
|
56
|
+
"# Create a new data pool\n",
|
|
57
|
+
"data_pool = client.data_pools.create_data_pool(name=\"Example Data Pool\")\n",
|
|
58
|
+
"\n",
|
|
59
|
+
"# Add a file to the data pool\n",
|
|
60
|
+
"file = client.data_pools.add_data_pool_file(\n",
|
|
61
|
+
" id=data_pool.id, filename=\"example.txt\", file=\"Example content of the file.\"\n",
|
|
62
|
+
")"
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"cell_type": "code",
|
|
67
|
+
"execution_count": null,
|
|
68
|
+
"metadata": {},
|
|
69
|
+
"outputs": [],
|
|
70
|
+
"source": [
|
|
71
|
+
"content = client.data_pools.get_data_pool_file(id=data_pool.id, file_id=file.id)\n",
|
|
72
|
+
"\n",
|
|
73
|
+
"content_string = \"\"\n",
|
|
74
|
+
"for chunk in content:\n",
|
|
75
|
+
" content_string += chunk.decode(\"utf-8\")\n",
|
|
76
|
+
"\n",
|
|
77
|
+
"content_string"
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"cell_type": "markdown",
|
|
82
|
+
"metadata": {},
|
|
83
|
+
"source": [
|
|
84
|
+
"### Streaming File Upload\n",
|
|
85
|
+
"\n",
|
|
86
|
+
"This example shows how to stream a file from disk and upload it to a data pool."
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"cell_type": "code",
|
|
91
|
+
"execution_count": null,
|
|
92
|
+
"metadata": {},
|
|
93
|
+
"outputs": [],
|
|
94
|
+
"source": [
|
|
95
|
+
"# First, let's create a sample file to upload\n",
|
|
96
|
+
"import tempfile\n",
|
|
97
|
+
"import os\n",
|
|
98
|
+
"\n",
|
|
99
|
+
"# Create a temporary file with some content\n",
|
|
100
|
+
"sample_content = \"\"\"This is a sample file for streaming upload.\n",
|
|
101
|
+
"It contains multiple lines of text.\n",
|
|
102
|
+
"Line 3 with some data.\n",
|
|
103
|
+
"Line 4 with more content.\n",
|
|
104
|
+
"End of file.\"\"\"\n",
|
|
105
|
+
"\n",
|
|
106
|
+
"# Create a temporary file\n",
|
|
107
|
+
"temp_file = tempfile.NamedTemporaryFile(mode=\"w\", suffix=\".txt\", delete=False)\n",
|
|
108
|
+
"temp_file.write(sample_content)\n",
|
|
109
|
+
"temp_file.close()\n",
|
|
110
|
+
"\n",
|
|
111
|
+
"print(f\"Created temporary file: {temp_file.name}\")\n",
|
|
112
|
+
"print(f\"File size: {os.path.getsize(temp_file.name)} bytes\")"
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"cell_type": "code",
|
|
117
|
+
"execution_count": null,
|
|
118
|
+
"metadata": {},
|
|
119
|
+
"outputs": [],
|
|
120
|
+
"source": [
|
|
121
|
+
"# Upload by opening file and reading in chunks\n",
|
|
122
|
+
"def stream_file_upload(file_path, data_pool_id, filename):\n",
|
|
123
|
+
" \"\"\"\n",
|
|
124
|
+
" Stream a file from disk and upload it to a data pool\n",
|
|
125
|
+
" \"\"\"\n",
|
|
126
|
+
" with open(file_path, \"rb\") as file_handle:\n",
|
|
127
|
+
" # Upload the file using the file handle\n",
|
|
128
|
+
" uploaded_file = client.data_pools.add_data_pool_file(\n",
|
|
129
|
+
" id=data_pool_id, filename=filename, file=file_handle\n",
|
|
130
|
+
" )\n",
|
|
131
|
+
" return uploaded_file\n",
|
|
132
|
+
"\n",
|
|
133
|
+
"\n",
|
|
134
|
+
"# Upload the temporary file\n",
|
|
135
|
+
"streamed_file = stream_file_upload(temp_file.name, data_pool.id, \"streamed_sample.txt\")\n",
|
|
136
|
+
"\n",
|
|
137
|
+
"print(f\"Uploaded file: {streamed_file.name}\")\n",
|
|
138
|
+
"print(f\"File ID: {streamed_file.id}\")\n",
|
|
139
|
+
"print(f\"Content length: {streamed_file.content_length}\")"
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"cell_type": "code",
|
|
144
|
+
"execution_count": null,
|
|
145
|
+
"metadata": {},
|
|
146
|
+
"outputs": [],
|
|
147
|
+
"source": [
|
|
148
|
+
"# Verify the uploaded files by downloading and checking content\n",
|
|
149
|
+
"def download_and_verify(data_pool_id, file_id, expected_content=None):\n",
|
|
150
|
+
" \"\"\"\n",
|
|
151
|
+
" Download a file and optionally verify its content\n",
|
|
152
|
+
" \"\"\"\n",
|
|
153
|
+
" print(f\"Downloading file {file_id}...\")\n",
|
|
154
|
+
"\n",
|
|
155
|
+
" # Get the file content as Iterator[bytes]\n",
|
|
156
|
+
" content_stream = client.data_pools.get_data_pool_file(\n",
|
|
157
|
+
" id=data_pool_id, file_id=file_id\n",
|
|
158
|
+
" )\n",
|
|
159
|
+
"\n",
|
|
160
|
+
" # Read all chunks and combine\n",
|
|
161
|
+
" content_bytes = b\"\"\n",
|
|
162
|
+
" for chunk in content_stream:\n",
|
|
163
|
+
" content_bytes += chunk\n",
|
|
164
|
+
"\n",
|
|
165
|
+
" # Decode to string\n",
|
|
166
|
+
" content_string = content_bytes.decode(\"utf-8\")\n",
|
|
167
|
+
"\n",
|
|
168
|
+
" print(f\"Downloaded content ({len(content_bytes)} bytes):\")\n",
|
|
169
|
+
" print(content_string[:100] + \"...\" if len(content_string) > 100 else content_string)\n",
|
|
170
|
+
"\n",
|
|
171
|
+
" if expected_content and content_string.strip() == expected_content.strip():\n",
|
|
172
|
+
" print(\"✅ Content verification passed!\")\n",
|
|
173
|
+
" elif expected_content:\n",
|
|
174
|
+
" print(\"❌ Content verification failed!\")\n",
|
|
175
|
+
"\n",
|
|
176
|
+
" return content_string\n",
|
|
177
|
+
"\n",
|
|
178
|
+
"\n",
|
|
179
|
+
"download_and_verify(data_pool.id, streamed_file.id, sample_content)"
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"cell_type": "code",
|
|
184
|
+
"execution_count": null,
|
|
185
|
+
"metadata": {},
|
|
186
|
+
"outputs": [],
|
|
187
|
+
"source": [
|
|
188
|
+
"# Remove the temporary file\n",
|
|
189
|
+
"try:\n",
|
|
190
|
+
" os.unlink(temp_file.name)\n",
|
|
191
|
+
" print(f\"Cleaned up temporary file: {temp_file.name}\")\n",
|
|
192
|
+
"except OSError as e:\n",
|
|
193
|
+
" print(f\"Error cleaning up temporary file: {e}\")"
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
],
|
|
197
|
+
"metadata": {
|
|
198
|
+
"kernelspec": {
|
|
199
|
+
"display_name": "planqk-api-sdk",
|
|
200
|
+
"language": "python",
|
|
201
|
+
"name": "python3"
|
|
202
|
+
},
|
|
203
|
+
"language_info": {
|
|
204
|
+
"codemirror_mode": {
|
|
205
|
+
"name": "ipython",
|
|
206
|
+
"version": 3
|
|
207
|
+
},
|
|
208
|
+
"file_extension": ".py",
|
|
209
|
+
"mimetype": "text/x-python",
|
|
210
|
+
"name": "python",
|
|
211
|
+
"nbconvert_exporter": "python",
|
|
212
|
+
"pygments_lexer": "ipython3",
|
|
213
|
+
"version": "3.11.11"
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
"nbformat": 4,
|
|
217
|
+
"nbformat_minor": 2
|
|
218
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@planqk/planqk-api-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "SDK to interact with official PLANQK API.",
|
|
5
|
+
"author": "Kipu Quantum GmbH",
|
|
6
|
+
"contributors": [
|
|
7
|
+
"Wurster, Michael <michael.wurster@kipu-quantum.com>"
|
|
8
|
+
],
|
|
9
|
+
"license": "Apache-2.0",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://gitlab.com/planqk-foss/planqk-api-sdk.git"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"types": "dist/index.d.ts",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "shx rm -rf dist && tsc -b",
|
|
18
|
+
"lint": "eslint",
|
|
19
|
+
"test": "vitest"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"form-data": "^4",
|
|
23
|
+
"form-data-encoder": "^4",
|
|
24
|
+
"formdata-node": "^6",
|
|
25
|
+
"js-base64": "^3",
|
|
26
|
+
"node-fetch": "^3",
|
|
27
|
+
"qs": "^6",
|
|
28
|
+
"readable-stream": "^4",
|
|
29
|
+
"url-join": "^5"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^22",
|
|
33
|
+
"@types/node-fetch": "^2",
|
|
34
|
+
"@types/qs": "^6",
|
|
35
|
+
"@types/url-join": "^4",
|
|
36
|
+
"dotenv": "^16",
|
|
37
|
+
"eslint": "^9",
|
|
38
|
+
"shx": "^0.3.4",
|
|
39
|
+
"typescript": "^5",
|
|
40
|
+
"typescript-eslint": "^8",
|
|
41
|
+
"vitest": "^3"
|
|
42
|
+
},
|
|
43
|
+
"private": false,
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"readme": "./README-node.md"
|
|
48
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from ._version import __version__
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.0"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from planqk.api.credentials import DefaultCredentialsProvider
|
|
5
|
+
from planqk.api.sdk import PlanqkApi
|
|
6
|
+
from planqk.api.sdk.data_pools.client import DataPoolsClient
|
|
7
|
+
|
|
8
|
+
_PLANQK_API_BASE_URL_NAME = "PLANQK_API_BASE_URL"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PlanqkApiClient:
|
|
12
|
+
def __init__(self, access_token: Optional[str] = None):
|
|
13
|
+
base_url = os.environ.get(_PLANQK_API_BASE_URL_NAME, "https://platform.planqk.de/qc-catalog")
|
|
14
|
+
credentials_provider = DefaultCredentialsProvider(access_token)
|
|
15
|
+
self._api = PlanqkApi(base_url=base_url, api_key=credentials_provider.get_access_token())
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def data_pools(self) -> DataPoolsClient:
|
|
19
|
+
return self._api.data_pools
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import platform
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from json import JSONDecodeError
|
|
6
|
+
|
|
7
|
+
_PERSONAL_ACCESS_TOKEN_NAME = "PLANQK_PERSONAL_ACCESS_TOKEN"
|
|
8
|
+
_CONFIG_FILE_PATH = "PLANQK_CONFIG_FILE_PATH"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CredentialUnavailableError(Exception):
|
|
12
|
+
"""
|
|
13
|
+
Exception raised when credentials are unavailable for authentication.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, message=None):
|
|
17
|
+
if message is None:
|
|
18
|
+
message = f"Credentials not found. Please set your personal access token as parameter, in the environment, or use 'planqk login' to authenticate."
|
|
19
|
+
super().__init__(message)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CredentialProvider(ABC):
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def get_access_token(self) -> str:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class EnvironmentCredential(CredentialProvider):
|
|
30
|
+
|
|
31
|
+
def get_access_token(self) -> str:
|
|
32
|
+
access_token = os.environ.get(_PERSONAL_ACCESS_TOKEN_NAME)
|
|
33
|
+
|
|
34
|
+
if not access_token:
|
|
35
|
+
raise CredentialUnavailableError(f"Environment variable {_PERSONAL_ACCESS_TOKEN_NAME} is not set")
|
|
36
|
+
|
|
37
|
+
return access_token
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_config_file_path():
|
|
41
|
+
config_file_path = os.environ.get(_CONFIG_FILE_PATH, None)
|
|
42
|
+
if not config_file_path:
|
|
43
|
+
if platform.system() == "Windows":
|
|
44
|
+
config_dir = os.path.join(os.getenv("LOCALAPPDATA"), "planqk")
|
|
45
|
+
else:
|
|
46
|
+
config_dir = os.path.join(os.path.expanduser("~"), ".config", "planqk")
|
|
47
|
+
config_file_path = os.path.join(config_dir, "config.json")
|
|
48
|
+
return config_file_path
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ConfigFileCredential(CredentialProvider):
|
|
52
|
+
def __init__(self):
|
|
53
|
+
self.config_file = get_config_file_path()
|
|
54
|
+
|
|
55
|
+
def get_access_token(self) -> str:
|
|
56
|
+
if not self.config_file:
|
|
57
|
+
raise CredentialUnavailableError("Config file location not set")
|
|
58
|
+
if not os.path.isfile(self.config_file):
|
|
59
|
+
raise CredentialUnavailableError(f"Config file at {self.config_file} does not exist")
|
|
60
|
+
try:
|
|
61
|
+
access_token = ConfigFileCredential.parse_file(self.config_file)
|
|
62
|
+
except JSONDecodeError:
|
|
63
|
+
raise CredentialUnavailableError("Failed to parse config file: Invalid JSON")
|
|
64
|
+
except KeyError as e:
|
|
65
|
+
raise CredentialUnavailableError(f"Failed to parse config file: Missing expected value - {str(e)}")
|
|
66
|
+
except Exception as e:
|
|
67
|
+
raise CredentialUnavailableError(f"Failed to parse config file: {str(e)}")
|
|
68
|
+
return access_token
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def parse_file(path) -> str:
|
|
72
|
+
with open(path, "r") as file:
|
|
73
|
+
data = json.load(file)
|
|
74
|
+
return data["auth"]["value"]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class StaticCredential(CredentialProvider):
|
|
78
|
+
def __init__(self, access_token=None):
|
|
79
|
+
self.access_token = access_token
|
|
80
|
+
|
|
81
|
+
def get_access_token(self) -> str:
|
|
82
|
+
if not self.access_token:
|
|
83
|
+
raise CredentialUnavailableError(f"Access token not set")
|
|
84
|
+
return self.access_token
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class DefaultCredentialsProvider(CredentialProvider):
|
|
88
|
+
def __init__(self, access_token=None):
|
|
89
|
+
self.credentials = [
|
|
90
|
+
StaticCredential(access_token),
|
|
91
|
+
EnvironmentCredential(),
|
|
92
|
+
ConfigFileCredential(),
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
def get_access_token(self) -> str:
|
|
96
|
+
for credential in self.credentials:
|
|
97
|
+
try:
|
|
98
|
+
return credential.get_access_token()
|
|
99
|
+
except CredentialUnavailableError:
|
|
100
|
+
# ignore and try the next credential provider
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
raise CredentialUnavailableError()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
# isort: skip_file
|
|
4
|
+
|
|
5
|
+
from .types import DataPoolDto, DataPoolDtoCurrentUserPermission, DataPoolFileDto, OauthScope
|
|
6
|
+
from .errors import BadRequestError, ForbiddenError, InternalServerError, NotFoundError, UnauthorizedError
|
|
7
|
+
from . import data_pools
|
|
8
|
+
from .client import AsyncPlanqkApi, PlanqkApi
|
|
9
|
+
from .environment import PlanqkApiEnvironment
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"AsyncPlanqkApi",
|
|
13
|
+
"BadRequestError",
|
|
14
|
+
"DataPoolDto",
|
|
15
|
+
"DataPoolDtoCurrentUserPermission",
|
|
16
|
+
"DataPoolFileDto",
|
|
17
|
+
"ForbiddenError",
|
|
18
|
+
"InternalServerError",
|
|
19
|
+
"NotFoundError",
|
|
20
|
+
"OauthScope",
|
|
21
|
+
"PlanqkApi",
|
|
22
|
+
"PlanqkApiEnvironment",
|
|
23
|
+
"UnauthorizedError",
|
|
24
|
+
"data_pools",
|
|
25
|
+
]
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
import typing
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
|
|
7
|
+
from .data_pools.client import AsyncDataPoolsClient, DataPoolsClient
|
|
8
|
+
from .environment import PlanqkApiEnvironment
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PlanqkApi:
|
|
12
|
+
"""
|
|
13
|
+
Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propagate to these functions.
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
base_url : typing.Optional[str]
|
|
18
|
+
The base url to use for requests from the client.
|
|
19
|
+
|
|
20
|
+
environment : PlanqkApiEnvironment
|
|
21
|
+
The environment to use for requests from the client. from .environment import PlanqkApiEnvironment
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
Defaults to PlanqkApiEnvironment.DEFAULT
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
api_key : str
|
|
30
|
+
headers : typing.Optional[typing.Dict[str, str]]
|
|
31
|
+
Additional headers to send with every request.
|
|
32
|
+
|
|
33
|
+
timeout : typing.Optional[float]
|
|
34
|
+
The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
|
|
35
|
+
|
|
36
|
+
follow_redirects : typing.Optional[bool]
|
|
37
|
+
Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.
|
|
38
|
+
|
|
39
|
+
httpx_client : typing.Optional[httpx.Client]
|
|
40
|
+
The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.
|
|
41
|
+
|
|
42
|
+
Examples
|
|
43
|
+
--------
|
|
44
|
+
from planqk import PlanqkApi
|
|
45
|
+
|
|
46
|
+
client = PlanqkApi(
|
|
47
|
+
api_key="YOUR_API_KEY",
|
|
48
|
+
)
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
*,
|
|
54
|
+
base_url: typing.Optional[str] = None,
|
|
55
|
+
environment: PlanqkApiEnvironment = PlanqkApiEnvironment.DEFAULT,
|
|
56
|
+
api_key: str,
|
|
57
|
+
headers: typing.Optional[typing.Dict[str, str]] = None,
|
|
58
|
+
timeout: typing.Optional[float] = None,
|
|
59
|
+
follow_redirects: typing.Optional[bool] = True,
|
|
60
|
+
httpx_client: typing.Optional[httpx.Client] = None,
|
|
61
|
+
):
|
|
62
|
+
_defaulted_timeout = (
|
|
63
|
+
timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
|
|
64
|
+
)
|
|
65
|
+
self._client_wrapper = SyncClientWrapper(
|
|
66
|
+
base_url=_get_base_url(base_url=base_url, environment=environment),
|
|
67
|
+
api_key=api_key,
|
|
68
|
+
headers=headers,
|
|
69
|
+
httpx_client=httpx_client
|
|
70
|
+
if httpx_client is not None
|
|
71
|
+
else httpx.Client(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
|
|
72
|
+
if follow_redirects is not None
|
|
73
|
+
else httpx.Client(timeout=_defaulted_timeout),
|
|
74
|
+
timeout=_defaulted_timeout,
|
|
75
|
+
)
|
|
76
|
+
self.data_pools = DataPoolsClient(client_wrapper=self._client_wrapper)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class AsyncPlanqkApi:
|
|
80
|
+
"""
|
|
81
|
+
Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propagate to these functions.
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
base_url : typing.Optional[str]
|
|
86
|
+
The base url to use for requests from the client.
|
|
87
|
+
|
|
88
|
+
environment : PlanqkApiEnvironment
|
|
89
|
+
The environment to use for requests from the client. from .environment import PlanqkApiEnvironment
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
Defaults to PlanqkApiEnvironment.DEFAULT
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
api_key : str
|
|
98
|
+
headers : typing.Optional[typing.Dict[str, str]]
|
|
99
|
+
Additional headers to send with every request.
|
|
100
|
+
|
|
101
|
+
timeout : typing.Optional[float]
|
|
102
|
+
The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
|
|
103
|
+
|
|
104
|
+
follow_redirects : typing.Optional[bool]
|
|
105
|
+
Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.
|
|
106
|
+
|
|
107
|
+
httpx_client : typing.Optional[httpx.AsyncClient]
|
|
108
|
+
The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.
|
|
109
|
+
|
|
110
|
+
Examples
|
|
111
|
+
--------
|
|
112
|
+
from planqk import AsyncPlanqkApi
|
|
113
|
+
|
|
114
|
+
client = AsyncPlanqkApi(
|
|
115
|
+
api_key="YOUR_API_KEY",
|
|
116
|
+
)
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
def __init__(
|
|
120
|
+
self,
|
|
121
|
+
*,
|
|
122
|
+
base_url: typing.Optional[str] = None,
|
|
123
|
+
environment: PlanqkApiEnvironment = PlanqkApiEnvironment.DEFAULT,
|
|
124
|
+
api_key: str,
|
|
125
|
+
headers: typing.Optional[typing.Dict[str, str]] = None,
|
|
126
|
+
timeout: typing.Optional[float] = None,
|
|
127
|
+
follow_redirects: typing.Optional[bool] = True,
|
|
128
|
+
httpx_client: typing.Optional[httpx.AsyncClient] = None,
|
|
129
|
+
):
|
|
130
|
+
_defaulted_timeout = (
|
|
131
|
+
timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
|
|
132
|
+
)
|
|
133
|
+
self._client_wrapper = AsyncClientWrapper(
|
|
134
|
+
base_url=_get_base_url(base_url=base_url, environment=environment),
|
|
135
|
+
api_key=api_key,
|
|
136
|
+
headers=headers,
|
|
137
|
+
httpx_client=httpx_client
|
|
138
|
+
if httpx_client is not None
|
|
139
|
+
else httpx.AsyncClient(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
|
|
140
|
+
if follow_redirects is not None
|
|
141
|
+
else httpx.AsyncClient(timeout=_defaulted_timeout),
|
|
142
|
+
timeout=_defaulted_timeout,
|
|
143
|
+
)
|
|
144
|
+
self.data_pools = AsyncDataPoolsClient(client_wrapper=self._client_wrapper)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _get_base_url(*, base_url: typing.Optional[str] = None, environment: PlanqkApiEnvironment) -> str:
|
|
148
|
+
if base_url is not None:
|
|
149
|
+
return base_url
|
|
150
|
+
elif environment is not None:
|
|
151
|
+
return environment.value
|
|
152
|
+
else:
|
|
153
|
+
raise Exception("Please pass in either base_url or environment to construct the client")
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
# isort: skip_file
|
|
4
|
+
|
|
5
|
+
from .api_error import ApiError
|
|
6
|
+
from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper
|
|
7
|
+
from .datetime_utils import serialize_datetime
|
|
8
|
+
from .file import File, convert_file_dict_to_httpx_tuples, with_content_type
|
|
9
|
+
from .http_client import AsyncHttpClient, HttpClient
|
|
10
|
+
from .http_response import AsyncHttpResponse, HttpResponse
|
|
11
|
+
from .jsonable_encoder import jsonable_encoder
|
|
12
|
+
from .pydantic_utilities import (
|
|
13
|
+
IS_PYDANTIC_V2,
|
|
14
|
+
UniversalBaseModel,
|
|
15
|
+
UniversalRootModel,
|
|
16
|
+
parse_obj_as,
|
|
17
|
+
universal_field_validator,
|
|
18
|
+
universal_root_validator,
|
|
19
|
+
update_forward_refs,
|
|
20
|
+
)
|
|
21
|
+
from .query_encoder import encode_query
|
|
22
|
+
from .remove_none_from_dict import remove_none_from_dict
|
|
23
|
+
from .request_options import RequestOptions
|
|
24
|
+
from .serialization import FieldMetadata, convert_and_respect_annotation_metadata
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"ApiError",
|
|
28
|
+
"AsyncClientWrapper",
|
|
29
|
+
"AsyncHttpClient",
|
|
30
|
+
"AsyncHttpResponse",
|
|
31
|
+
"BaseClientWrapper",
|
|
32
|
+
"FieldMetadata",
|
|
33
|
+
"File",
|
|
34
|
+
"HttpClient",
|
|
35
|
+
"HttpResponse",
|
|
36
|
+
"IS_PYDANTIC_V2",
|
|
37
|
+
"RequestOptions",
|
|
38
|
+
"SyncClientWrapper",
|
|
39
|
+
"UniversalBaseModel",
|
|
40
|
+
"UniversalRootModel",
|
|
41
|
+
"convert_and_respect_annotation_metadata",
|
|
42
|
+
"convert_file_dict_to_httpx_tuples",
|
|
43
|
+
"encode_query",
|
|
44
|
+
"jsonable_encoder",
|
|
45
|
+
"parse_obj_as",
|
|
46
|
+
"remove_none_from_dict",
|
|
47
|
+
"serialize_datetime",
|
|
48
|
+
"universal_field_validator",
|
|
49
|
+
"universal_root_validator",
|
|
50
|
+
"update_forward_refs",
|
|
51
|
+
"with_content_type",
|
|
52
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ApiError(Exception):
|
|
7
|
+
headers: Optional[Dict[str, str]]
|
|
8
|
+
status_code: Optional[int]
|
|
9
|
+
body: Any
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
*,
|
|
14
|
+
headers: Optional[Dict[str, str]] = None,
|
|
15
|
+
status_code: Optional[int] = None,
|
|
16
|
+
body: Any = None,
|
|
17
|
+
) -> None:
|
|
18
|
+
self.headers = headers
|
|
19
|
+
self.status_code = status_code
|
|
20
|
+
self.body = body
|
|
21
|
+
|
|
22
|
+
def __str__(self) -> str:
|
|
23
|
+
return f"headers: {self.headers}, status_code: {self.status_code}, body: {self.body}"
|