lkr-dev-cli 0.0.30__py3-none-any.whl → 0.0.31__py3-none-any.whl
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.
- lkr/tools/classes.py +5 -4
- lkr/tools/main.py +1 -1
- {lkr_dev_cli-0.0.30.dist-info → lkr_dev_cli-0.0.31.dist-info}/METADATA +100 -11
- {lkr_dev_cli-0.0.30.dist-info → lkr_dev_cli-0.0.31.dist-info}/RECORD +7 -7
- {lkr_dev_cli-0.0.30.dist-info → lkr_dev_cli-0.0.31.dist-info}/WHEEL +0 -0
- {lkr_dev_cli-0.0.30.dist-info → lkr_dev_cli-0.0.31.dist-info}/entry_points.txt +0 -0
- {lkr_dev_cli-0.0.30.dist-info → lkr_dev_cli-0.0.31.dist-info}/licenses/LICENSE +0 -0
lkr/tools/classes.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
from typing import Literal, Optional, Self, cast
|
2
2
|
|
3
|
-
from fastapi import Request
|
4
3
|
from looker_sdk.sdk.api40.methods import Looker40SDK
|
5
4
|
from looker_sdk.sdk.api40.models import (
|
6
5
|
UserAttributeGroupValue,
|
@@ -46,10 +45,12 @@ class UserAttributeUpdater(BaseModel):
|
|
46
45
|
)
|
47
46
|
return self
|
48
47
|
|
49
|
-
def get_request_authorization_for_value(self,
|
50
|
-
authorization_token =
|
48
|
+
def get_request_authorization_for_value(self, headers: list[tuple[str, str]]):
|
49
|
+
authorization_token = next(
|
50
|
+
(header for header in headers if header[0] == "Authorization"), None
|
51
|
+
)
|
51
52
|
if authorization_token:
|
52
|
-
self.value = authorization_token
|
53
|
+
self.value = authorization_token[1]
|
53
54
|
else:
|
54
55
|
logger.error("No authorization token found")
|
55
56
|
|
lkr/tools/main.py
CHANGED
@@ -22,7 +22,7 @@ def user_attribute_updater(
|
|
22
22
|
@api.post("/identity_token")
|
23
23
|
def identity_token(request: Request, body: UserAttributeUpdater):
|
24
24
|
try:
|
25
|
-
body.get_request_authorization_for_value(request)
|
25
|
+
body.get_request_authorization_for_value(request.headers.items())
|
26
26
|
body.update_user_attribute_value()
|
27
27
|
raw_urls = os.getenv("LOOKER_WHITELISTED_BASE_URLS", "")
|
28
28
|
whitelisted_base_urls = (
|
@@ -1,23 +1,32 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: lkr-dev-cli
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.31
|
4
4
|
Summary: lkr: a command line interface for looker
|
5
5
|
Author: bwebs
|
6
6
|
License-Expression: MIT
|
7
7
|
License-File: LICENSE
|
8
8
|
Requires-Python: >=3.12
|
9
9
|
Requires-Dist: cryptography>=42.0.0
|
10
|
-
Requires-Dist: duckdb>=1.2.2
|
11
|
-
Requires-Dist: fastapi>=0.115.12
|
12
10
|
Requires-Dist: looker-sdk>=25.4.0
|
13
|
-
Requires-Dist: mcp[cli]>=1.9.2
|
14
11
|
Requires-Dist: pydantic>=2.11.4
|
15
12
|
Requires-Dist: pydash>=8.0.5
|
16
13
|
Requires-Dist: questionary>=2.1.0
|
17
14
|
Requires-Dist: requests>=2.31.0
|
18
|
-
Requires-Dist: selenium>=4.32.0
|
19
15
|
Requires-Dist: structlog>=25.3.0
|
20
16
|
Requires-Dist: typer>=0.15.2
|
17
|
+
Provides-Extra: all
|
18
|
+
Requires-Dist: duckdb>=1.2.2; extra == 'all'
|
19
|
+
Requires-Dist: fastapi>=0.115.12; extra == 'all'
|
20
|
+
Requires-Dist: mcp[cli]>=1.9.2; extra == 'all'
|
21
|
+
Requires-Dist: selenium>=4.32.0; extra == 'all'
|
22
|
+
Provides-Extra: embed-observability
|
23
|
+
Requires-Dist: fastapi>=0.115.12; extra == 'embed-observability'
|
24
|
+
Requires-Dist: selenium>=4.32.0; extra == 'embed-observability'
|
25
|
+
Provides-Extra: mcp
|
26
|
+
Requires-Dist: duckdb>=1.2.2; extra == 'mcp'
|
27
|
+
Requires-Dist: mcp[cli]>=1.9.2; extra == 'mcp'
|
28
|
+
Provides-Extra: user-attribute-updater
|
29
|
+
Requires-Dist: fastapi>=0.115.12; extra == 'user-attribute-updater'
|
21
30
|
Description-Content-Type: text/markdown
|
22
31
|
|
23
32
|
# lkr cli
|
@@ -214,10 +223,13 @@ This can also be used to stress test your Looker environment as it serves an API
|
|
214
223
|
## User Attribute Updater (OIDC Token)
|
215
224
|
|
216
225
|
1. Create a new cloud run using the `lkr-cli` public docker image `us-central1-docker.pkg.dev/lkr-dev-production/lkr-cli/cli:latest`
|
217
|
-
2. Put in the environment variables LOOKERSDK_CLIENT_ID, LOOKERSDK_CLIENT_SECRET, LOOKERSDK_BASE_URL, LOOKER_WHITELISTED_BASE_URLS. The `LOOKER_WHITELISTED_BASE_URLS` would be the same url as the `LOOKERSDK_BASE_URL` if you are only using this for a single Looker instance. For more advanced use cases, you can set the `LOOKER_WHITELISTED_BASE_URLS` to a comma separated list of urls. The body of the request also accepts a `base_url`, `client_id`, and `client_secret` key that will override these settings.
|
218
|
-
3.
|
219
|
-
|
220
|
-
|
226
|
+
2. Put in the environment variables LOOKERSDK_CLIENT_ID, LOOKERSDK_CLIENT_SECRET, LOOKERSDK_BASE_URL, LOOKER_WHITELISTED_BASE_URLS. The `LOOKER_WHITELISTED_BASE_URLS` would be the same url as the `LOOKERSDK_BASE_URL` if you are only using this for a single Looker instance. For more advanced use cases, you can set the `LOOKER_WHITELISTED_BASE_URLS` to a comma separated list of urls. The body of the request also accepts a `base_url`, `client_id`, and `client_secret` key that will override these settings. See example [`gcloud` command](#example-gcloud-command)
|
227
|
+
3. For the command and arguments use:
|
228
|
+
- command: `lkr`
|
229
|
+
- args: `tools` `user-attribute-updater`
|
230
|
+
4. Deploy the cloud run
|
231
|
+
5. Retrieve the URL of the cloud run
|
232
|
+
6. Create the user attribute
|
221
233
|
- Name: cloud_run_access_token
|
222
234
|
- Data Type: String
|
223
235
|
- User Access: None
|
@@ -250,6 +262,23 @@ This can also be used to stress test your Looker environment as it serves an API
|
|
250
262
|
9. Check the logs of the cloud run to see if there was a 200 response
|
251
263
|
|
252
264
|
|
265
|
+
### Example `gcloud` command
|
266
|
+
```bash
|
267
|
+
export REGION=<your region>
|
268
|
+
export PROJECT=<your project id>
|
269
|
+
|
270
|
+
gcloud run deploy lkr-access-token-updater \
|
271
|
+
--image us-central1-docker.pkg.dev/lkr-dev-production/lkr-cli/cli:latest \
|
272
|
+
--command lkr \
|
273
|
+
--args tools,user-attribute-updater \
|
274
|
+
--platform managed \
|
275
|
+
--region $REGION \
|
276
|
+
--project $PROJECT \
|
277
|
+
--cpu 1 \
|
278
|
+
--memory 2Gi \
|
279
|
+
--set-env-vars LOOKERSDK_CLIENT_ID=<your client id>,LOOKERSDK_CLIENT_SECRET=<your client secret>,LOOKERSDK_BASE_URL=<your instance url>,LOOKER_WHITELISTED_BASE_URLS=<your instance url>
|
280
|
+
```
|
281
|
+
|
253
282
|
## UserAttributeUpdater `lkr-dev-cli`
|
254
283
|
|
255
284
|
Exported from the `lkr-dev-cli` package is the `UserAttributeUpdater` pydantic class. This class has all the necessary logic to update a user attribute value.
|
@@ -301,12 +330,12 @@ from lkr import UserAttributeUpdater
|
|
301
330
|
def request_authorization(request: Request):
|
302
331
|
body = await request.json()
|
303
332
|
updater = UserAttributeUpdater.model_validate(body)
|
304
|
-
updater.get_request_authorization_for_value(request)
|
333
|
+
updater.get_request_authorization_for_value(request.headers.items())
|
305
334
|
updater.update_user_attribute_value()
|
306
335
|
|
307
336
|
@app.post("/as_body")
|
308
337
|
def as_body(request: Request, body: UserAttributeUpdater):
|
309
|
-
body.get_request_authorization_for_value(request)
|
338
|
+
body.get_request_authorization_for_value(request.headers.items())
|
310
339
|
body.update_user_attribute_value()
|
311
340
|
|
312
341
|
@app.post("/assigning_value")
|
@@ -317,4 +346,64 @@ def assigning_value(request: Request):
|
|
317
346
|
)
|
318
347
|
updater.value = request.headers.get("my_custom_header")
|
319
348
|
updater.update_user_attribute_value()
|
349
|
+
|
350
|
+
@app.delete("/:user_attribute_name/:email")
|
351
|
+
def delete_user_attribute(user_attribute_name: str, email: str):
|
352
|
+
updater = UserAttributeUpdater(
|
353
|
+
user_attribute=user_attribute_name,
|
354
|
+
update_type="user",
|
355
|
+
email=email,
|
356
|
+
)
|
357
|
+
updater.delete_user_attribute_value()
|
358
|
+
|
359
|
+
## Optional Dependencies
|
360
|
+
|
361
|
+
The `lkr` CLI supports optional dependencies that enable additional functionality. You can install these individually or all at once.
|
362
|
+
|
363
|
+
### Available Extras
|
364
|
+
|
365
|
+
- **`mcp`**: Enables the MCP (Model Context Protocol) server functionality
|
366
|
+
- Includes: `mcp[cli]>=1.9.2`, `duckdb>=1.2.2`
|
367
|
+
- **`embed-observability`**: Enables the observability embed monitoring features
|
368
|
+
- Includes: `fastapi>=0.115.12`, `selenium>=4.32.0`
|
369
|
+
- **`user-attribute-updater`**: Enables the user attribute updater functionality
|
370
|
+
- Includes: `fastapi>=0.115.12`
|
371
|
+
|
372
|
+
### Installing Optional Dependencies
|
373
|
+
|
374
|
+
**Install all optional dependencies:**
|
375
|
+
```bash
|
376
|
+
uv sync --extra all
|
377
|
+
```
|
378
|
+
|
379
|
+
**Install specific extras:**
|
380
|
+
```bash
|
381
|
+
# Install MCP functionality
|
382
|
+
uv sync --extra mcp
|
383
|
+
|
384
|
+
# Install observability features
|
385
|
+
uv sync --extra embed-observability
|
386
|
+
|
387
|
+
# Install user attribute updater
|
388
|
+
uv sync --extra user-attribute-updater
|
389
|
+
|
390
|
+
# Install multiple extras
|
391
|
+
uv sync --extra mcp --extra embed-observability
|
392
|
+
```
|
393
|
+
|
394
|
+
**Using pip:**
|
395
|
+
```bash
|
396
|
+
# Install all optional dependencies
|
397
|
+
pip install lkr-dev-cli[all]
|
398
|
+
|
399
|
+
# Install specific extras
|
400
|
+
pip install lkr-dev-cli[mcp,embed-observability,user-attribute-updater]
|
320
401
|
```
|
402
|
+
|
403
|
+
### What Each Extra Enables
|
404
|
+
|
405
|
+
- **`mcp`**: Use the MCP server with tools like Cursor for enhanced IDE integration
|
406
|
+
- **`embed-observability`**: Run the observability embed server for monitoring Looker dashboard performance
|
407
|
+
- **`user-attribute-updater`**: Deploy the user attribute updater service for OIDC token management
|
408
|
+
|
409
|
+
All extras are designed to work together seamlessly, and installing `all` is equivalent to installing all individual extras.
|
@@ -16,10 +16,10 @@ lkr/observability/classes.py,sha256=LgGuUnY-J1csPrlAKnw4PPOqOfbvaOx2cxENlQgJYcE,
|
|
16
16
|
lkr/observability/embed_container.html,sha256=IcDG-QVsYYNGQGrkDrx9OMZ2Pmo4C8oAjRHddFQ7Tlw,2939
|
17
17
|
lkr/observability/main.py,sha256=XbejIdqhNNUMqHVezb5EnLaJ32dO9-Bt0o5d8lc0kyw,9544
|
18
18
|
lkr/observability/utils.py,sha256=UpaBrp_ufaXLoz4p3xG3K6lHKBpP9wBhvP8rDmeGoWg,2148
|
19
|
-
lkr/tools/classes.py,sha256=
|
20
|
-
lkr/tools/main.py,sha256=
|
21
|
-
lkr_dev_cli-0.0.
|
22
|
-
lkr_dev_cli-0.0.
|
23
|
-
lkr_dev_cli-0.0.
|
24
|
-
lkr_dev_cli-0.0.
|
25
|
-
lkr_dev_cli-0.0.
|
19
|
+
lkr/tools/classes.py,sha256=ZyRRCQjjwV4WVWGmKlTfXiLiOGUf67XgrboYhOLuLts,7508
|
20
|
+
lkr/tools/main.py,sha256=u9O5JgGVFscav9wFcrHd5ZPUUue_KpeK0QukYKqzros,2683
|
21
|
+
lkr_dev_cli-0.0.31.dist-info/METADATA,sha256=8QimDm78NO_wvLUt3XJ_SlwdMkCY3pk5Jt8KY1FuGxo,18527
|
22
|
+
lkr_dev_cli-0.0.31.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
23
|
+
lkr_dev_cli-0.0.31.dist-info/entry_points.txt,sha256=nn2sFMGDpwUVE61ZUpbDPnQZkW7Gc08nV-tyLGo8q34,37
|
24
|
+
lkr_dev_cli-0.0.31.dist-info/licenses/LICENSE,sha256=hKnCOORW1JRE_M2vStz8dblS5u1iR-2VpqS9xagKNa0,1063
|
25
|
+
lkr_dev_cli-0.0.31.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|