lkr-dev-cli 0.0.31__tar.gz → 0.0.33__tar.gz
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_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/PKG-INFO +42 -28
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/README.md +34 -21
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/auth/main.py +17 -5
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/auth_service.py +4 -3
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/logger.py +33 -22
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/main.py +25 -6
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/observability/main.py +2 -0
- lkr_dev_cli-0.0.33/lkr/tools/main.py +232 -0
- lkr_dev_cli-0.0.33/lkr/tools/permission_deprecation.py +193 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr.md +21 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/pyproject.toml +10 -9
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/tests/test_dependency_resolution.py +59 -1
- lkr_dev_cli-0.0.33/tests/test_permission_deprecation.py +176 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/uv.lock +327 -21
- lkr_dev_cli-0.0.31/lkr/tools/main.py +0 -84
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/.github/workflows/release.yml +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/.github/workflows/test-dependencies.yml +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/.gitignore +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/.python-version +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/.vscode/launch.json +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/.vscode/settings.json +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/Dockerfile +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/LICENSE +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/Makefile +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/cloudbuild.yaml +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/__init__.py +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/auth/__init__.py +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/auth/oauth.py +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/classes.py +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/constants.py +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/custom_types.py +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/exceptions.py +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/mcp/classes.py +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/mcp/main.py +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/mcp/utils.py +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/observability/classes.py +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/observability/embed_container.html +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/observability/utils.py +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/lkr/tools/classes.py +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/tests/TESTING.md +0 -0
- {lkr_dev_cli-0.0.31 → lkr_dev_cli-0.0.33}/tests/test_deps.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lkr-dev-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.33
|
|
4
4
|
Summary: lkr: a command line interface for looker
|
|
5
5
|
Author: bwebs
|
|
6
6
|
License-Expression: MIT
|
|
@@ -16,17 +16,18 @@ Requires-Dist: structlog>=25.3.0
|
|
|
16
16
|
Requires-Dist: typer>=0.15.2
|
|
17
17
|
Provides-Extra: all
|
|
18
18
|
Requires-Dist: duckdb>=1.2.2; extra == 'all'
|
|
19
|
-
Requires-Dist: fastapi>=0.115.12; extra == 'all'
|
|
19
|
+
Requires-Dist: fastapi[standard]>=0.115.12; extra == 'all'
|
|
20
20
|
Requires-Dist: mcp[cli]>=1.9.2; extra == 'all'
|
|
21
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
22
|
Provides-Extra: mcp
|
|
26
23
|
Requires-Dist: duckdb>=1.2.2; extra == 'mcp'
|
|
24
|
+
Requires-Dist: fastapi[standard]>=0.115.12; extra == 'mcp'
|
|
27
25
|
Requires-Dist: mcp[cli]>=1.9.2; extra == 'mcp'
|
|
28
|
-
Provides-Extra:
|
|
29
|
-
Requires-Dist: fastapi>=0.115.12; extra == '
|
|
26
|
+
Provides-Extra: observability
|
|
27
|
+
Requires-Dist: fastapi[standard]>=0.115.12; extra == 'observability'
|
|
28
|
+
Requires-Dist: selenium>=4.32.0; extra == 'observability'
|
|
29
|
+
Provides-Extra: tools
|
|
30
|
+
Requires-Dist: fastapi[standard]>=0.115.12; extra == 'tools'
|
|
30
31
|
Description-Content-Type: text/markdown
|
|
31
32
|
|
|
32
33
|
# lkr cli
|
|
@@ -35,9 +36,9 @@ The `lkr` cli is a tool for interacting with Looker. It combines Looker's SDK an
|
|
|
35
36
|
|
|
36
37
|
## Usage
|
|
37
38
|
|
|
38
|
-
`uv` makes everyone's life easier. Go [install it](https://docs.astral.sh/uv/getting-started/installation/). You can start using `lkr` by running `
|
|
39
|
+
`uv` makes everyone's life easier. Go [install it](https://docs.astral.sh/uv/getting-started/installation/). You can start using `lkr` by running `uvx --from lkr-dev-cli[all] lkr --help`.
|
|
39
40
|
|
|
40
|
-
Alternatively, you can install `lkr` with `pip install lkr-dev-cli` and use commands directly like `lkr <command>`.
|
|
41
|
+
Alternatively, you can install `lkr` with `pip install lkr-dev-cli[all]` and use commands directly like `lkr <command>`.
|
|
41
42
|
|
|
42
43
|
We also have a public docker image that you can use to run `lkr` commands.
|
|
43
44
|
|
|
@@ -55,7 +56,7 @@ See the [prerequisites section](#oauth2-prerequisites)
|
|
|
55
56
|
Login to `lkr`
|
|
56
57
|
|
|
57
58
|
```bash
|
|
58
|
-
|
|
59
|
+
uvx --from lkr-dev-cli[all] lkr auth login
|
|
59
60
|
```
|
|
60
61
|
|
|
61
62
|
- Select a new instance
|
|
@@ -63,12 +64,12 @@ uv run --with lkr-dev-cli lkr auth login
|
|
|
63
64
|
- Choose whether you want this login to use production or development mode
|
|
64
65
|
- Give it a name
|
|
65
66
|
|
|
66
|
-
You will be redirected to the Looker OAuth authorization page, click Allow. If you do not see an allow button, the [prerequisites](#prerequisites) were not done properly.
|
|
67
|
+
You will be redirected to the Looker OAuth authorization page, click Allow. If you do not see an allow button, the [prerequisites](#oauth2-prerequisites) were not done properly.
|
|
67
68
|
|
|
68
69
|
If everything is successful, you will see `Successfully authenticated!`. Test it with
|
|
69
70
|
|
|
70
71
|
```bash
|
|
71
|
-
|
|
72
|
+
uvx --from lkr-dev-cli[all] lkr auth whoami
|
|
72
73
|
```
|
|
73
74
|
|
|
74
75
|
### Using API Key
|
|
@@ -76,7 +77,7 @@ uv run --with lkr-dev-cli lkr auth whoami
|
|
|
76
77
|
If you provide environment variables for `LOOKERSDK_CLIENT_ID`, `LOOKERSDK_CLIENT_SECRET`, and `LOOKERSDK_BASE_URL`, `lkr` will use the API key to authenticate and the commands. We also support command line arguments to pass in the client id, client secret, and base url.
|
|
77
78
|
|
|
78
79
|
```bash
|
|
79
|
-
|
|
80
|
+
uvx --from lkr-dev-cli[all] lkr --client-id <your client id> --client-secret <your client secret> --base-url <your instance url> auth whoami
|
|
80
81
|
```
|
|
81
82
|
|
|
82
83
|
|
|
@@ -112,7 +113,7 @@ Built into the `lkr` is an MCP server. Right now its tools are based on helping
|
|
|
112
113
|
"mcpServers": {
|
|
113
114
|
"lkr-mcp": {
|
|
114
115
|
"command": "uv",
|
|
115
|
-
"args": ["run", "--with", "lkr-dev-cli", "lkr", "mcp", "run"]
|
|
116
|
+
"args": ["run", "--with", "lkr-dev-cli[all]", "lkr", "mcp", "run"]
|
|
116
117
|
},
|
|
117
118
|
"lkr-mcp-docker": {
|
|
118
119
|
"command": "docker",
|
|
@@ -356,18 +357,39 @@ def delete_user_attribute(user_attribute_name: str, email: str):
|
|
|
356
357
|
)
|
|
357
358
|
updater.delete_user_attribute_value()
|
|
358
359
|
|
|
360
|
+
## Permission Deprecation Tool
|
|
361
|
+
|
|
362
|
+
The `schedule-download-deprecation` tool helps Looker admins ensure that users do not lose access to models they already have when Looker moves towards more granular model-specific permissions for scheduling and downloading.
|
|
363
|
+
|
|
364
|
+
### How it helps
|
|
365
|
+
Currently, some permissions in Looker can be granted instance-wide. In the future, these permissions may need to be explicitly granted at the model level (via Model Sets). This tool audits all active users and identifies those who:
|
|
366
|
+
- Have "target permissions" (like `download_with_limit`, `schedule_look_emails`, etc.) instance-wide.
|
|
367
|
+
- Do **not** have those same permissions for specific models they otherwise have access to.
|
|
368
|
+
|
|
369
|
+
By running this tool, an admin can proactively identify and fix permission gaps before any deprecation takes effect, ensuring a seamless experience for end-users.
|
|
370
|
+
|
|
371
|
+
### Usage
|
|
372
|
+
This command should be run by a **Looker Admin**.
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
uvx --from lkr-dev-cli[all] lkr tools schedule-download-deprecation
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Options:
|
|
379
|
+
- `--csv`: Export the results to a CSV file for easier analysis of large instances.
|
|
380
|
+
- `--unfiltered`: Show all users, including those who have all required permissions across all models.
|
|
381
|
+
- `--model-offset`: Slice the table output to show different sets of models (the table shows 5 models at a time).
|
|
382
|
+
|
|
383
|
+
|
|
359
384
|
## Optional Dependencies
|
|
360
385
|
|
|
361
386
|
The `lkr` CLI supports optional dependencies that enable additional functionality. You can install these individually or all at once.
|
|
362
387
|
|
|
363
388
|
### Available Extras
|
|
364
389
|
|
|
365
|
-
- **`mcp`**: Enables the MCP (Model Context Protocol) server functionality
|
|
366
|
-
|
|
367
|
-
- **`
|
|
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`
|
|
390
|
+
- **`mcp`**: Enables the MCP (Model Context Protocol) server functionality and `lkr mcp` commands
|
|
391
|
+
- **`observability`**: Enables the observability embed monitoring features and `lkr observability` commands
|
|
392
|
+
- **`tools`**: Enables the user attribute updater functionality and `lkr tools` commands
|
|
371
393
|
|
|
372
394
|
### Installing Optional Dependencies
|
|
373
395
|
|
|
@@ -399,11 +421,3 @@ pip install lkr-dev-cli[all]
|
|
|
399
421
|
# Install specific extras
|
|
400
422
|
pip install lkr-dev-cli[mcp,embed-observability,user-attribute-updater]
|
|
401
423
|
```
|
|
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.
|
|
@@ -4,9 +4,9 @@ The `lkr` cli is a tool for interacting with Looker. It combines Looker's SDK an
|
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
7
|
-
`uv` makes everyone's life easier. Go [install it](https://docs.astral.sh/uv/getting-started/installation/). You can start using `lkr` by running `
|
|
7
|
+
`uv` makes everyone's life easier. Go [install it](https://docs.astral.sh/uv/getting-started/installation/). You can start using `lkr` by running `uvx --from lkr-dev-cli[all] lkr --help`.
|
|
8
8
|
|
|
9
|
-
Alternatively, you can install `lkr` with `pip install lkr-dev-cli` and use commands directly like `lkr <command>`.
|
|
9
|
+
Alternatively, you can install `lkr` with `pip install lkr-dev-cli[all]` and use commands directly like `lkr <command>`.
|
|
10
10
|
|
|
11
11
|
We also have a public docker image that you can use to run `lkr` commands.
|
|
12
12
|
|
|
@@ -24,7 +24,7 @@ See the [prerequisites section](#oauth2-prerequisites)
|
|
|
24
24
|
Login to `lkr`
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
|
-
|
|
27
|
+
uvx --from lkr-dev-cli[all] lkr auth login
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
- Select a new instance
|
|
@@ -32,12 +32,12 @@ uv run --with lkr-dev-cli lkr auth login
|
|
|
32
32
|
- Choose whether you want this login to use production or development mode
|
|
33
33
|
- Give it a name
|
|
34
34
|
|
|
35
|
-
You will be redirected to the Looker OAuth authorization page, click Allow. If you do not see an allow button, the [prerequisites](#prerequisites) were not done properly.
|
|
35
|
+
You will be redirected to the Looker OAuth authorization page, click Allow. If you do not see an allow button, the [prerequisites](#oauth2-prerequisites) were not done properly.
|
|
36
36
|
|
|
37
37
|
If everything is successful, you will see `Successfully authenticated!`. Test it with
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
|
|
40
|
+
uvx --from lkr-dev-cli[all] lkr auth whoami
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
### Using API Key
|
|
@@ -45,7 +45,7 @@ uv run --with lkr-dev-cli lkr auth whoami
|
|
|
45
45
|
If you provide environment variables for `LOOKERSDK_CLIENT_ID`, `LOOKERSDK_CLIENT_SECRET`, and `LOOKERSDK_BASE_URL`, `lkr` will use the API key to authenticate and the commands. We also support command line arguments to pass in the client id, client secret, and base url.
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
|
|
48
|
+
uvx --from lkr-dev-cli[all] lkr --client-id <your client id> --client-secret <your client secret> --base-url <your instance url> auth whoami
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
|
|
@@ -81,7 +81,7 @@ Built into the `lkr` is an MCP server. Right now its tools are based on helping
|
|
|
81
81
|
"mcpServers": {
|
|
82
82
|
"lkr-mcp": {
|
|
83
83
|
"command": "uv",
|
|
84
|
-
"args": ["run", "--with", "lkr-dev-cli", "lkr", "mcp", "run"]
|
|
84
|
+
"args": ["run", "--with", "lkr-dev-cli[all]", "lkr", "mcp", "run"]
|
|
85
85
|
},
|
|
86
86
|
"lkr-mcp-docker": {
|
|
87
87
|
"command": "docker",
|
|
@@ -325,18 +325,39 @@ def delete_user_attribute(user_attribute_name: str, email: str):
|
|
|
325
325
|
)
|
|
326
326
|
updater.delete_user_attribute_value()
|
|
327
327
|
|
|
328
|
+
## Permission Deprecation Tool
|
|
329
|
+
|
|
330
|
+
The `schedule-download-deprecation` tool helps Looker admins ensure that users do not lose access to models they already have when Looker moves towards more granular model-specific permissions for scheduling and downloading.
|
|
331
|
+
|
|
332
|
+
### How it helps
|
|
333
|
+
Currently, some permissions in Looker can be granted instance-wide. In the future, these permissions may need to be explicitly granted at the model level (via Model Sets). This tool audits all active users and identifies those who:
|
|
334
|
+
- Have "target permissions" (like `download_with_limit`, `schedule_look_emails`, etc.) instance-wide.
|
|
335
|
+
- Do **not** have those same permissions for specific models they otherwise have access to.
|
|
336
|
+
|
|
337
|
+
By running this tool, an admin can proactively identify and fix permission gaps before any deprecation takes effect, ensuring a seamless experience for end-users.
|
|
338
|
+
|
|
339
|
+
### Usage
|
|
340
|
+
This command should be run by a **Looker Admin**.
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
uvx --from lkr-dev-cli[all] lkr tools schedule-download-deprecation
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Options:
|
|
347
|
+
- `--csv`: Export the results to a CSV file for easier analysis of large instances.
|
|
348
|
+
- `--unfiltered`: Show all users, including those who have all required permissions across all models.
|
|
349
|
+
- `--model-offset`: Slice the table output to show different sets of models (the table shows 5 models at a time).
|
|
350
|
+
|
|
351
|
+
|
|
328
352
|
## Optional Dependencies
|
|
329
353
|
|
|
330
354
|
The `lkr` CLI supports optional dependencies that enable additional functionality. You can install these individually or all at once.
|
|
331
355
|
|
|
332
356
|
### Available Extras
|
|
333
357
|
|
|
334
|
-
- **`mcp`**: Enables the MCP (Model Context Protocol) server functionality
|
|
335
|
-
|
|
336
|
-
- **`
|
|
337
|
-
- Includes: `fastapi>=0.115.12`, `selenium>=4.32.0`
|
|
338
|
-
- **`user-attribute-updater`**: Enables the user attribute updater functionality
|
|
339
|
-
- Includes: `fastapi>=0.115.12`
|
|
358
|
+
- **`mcp`**: Enables the MCP (Model Context Protocol) server functionality and `lkr mcp` commands
|
|
359
|
+
- **`observability`**: Enables the observability embed monitoring features and `lkr observability` commands
|
|
360
|
+
- **`tools`**: Enables the user attribute updater functionality and `lkr tools` commands
|
|
340
361
|
|
|
341
362
|
### Installing Optional Dependencies
|
|
342
363
|
|
|
@@ -368,11 +389,3 @@ pip install lkr-dev-cli[all]
|
|
|
368
389
|
# Install specific extras
|
|
369
390
|
pip install lkr-dev-cli[mcp,embed-observability,user-attribute-updater]
|
|
370
391
|
```
|
|
371
|
-
|
|
372
|
-
### What Each Extra Enables
|
|
373
|
-
|
|
374
|
-
- **`mcp`**: Use the MCP server with tools like Cursor for enhanced IDE integration
|
|
375
|
-
- **`embed-observability`**: Run the observability embed server for monitoring Looker dashboard performance
|
|
376
|
-
- **`user-attribute-updater`**: Deploy the user attribute updater service for OIDC token management
|
|
377
|
-
|
|
378
|
-
All extras are designed to work together seamlessly, and installing `all` is equivalent to installing all individual extras.
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import urllib.parse
|
|
2
2
|
from typing import Annotated, List, Union
|
|
3
3
|
|
|
4
|
-
import questionary
|
|
5
4
|
import typer
|
|
6
5
|
from looker_sdk.rtl.auth_token import AccessToken, AuthToken
|
|
7
|
-
from rich.console import Console
|
|
8
|
-
from rich.table import Table
|
|
9
6
|
|
|
10
7
|
from lkr.auth.oauth import OAuth2PKCE
|
|
11
8
|
from lkr.auth_service import get_auth
|
|
12
9
|
from lkr.logger import logger
|
|
13
10
|
|
|
11
|
+
QUESTIONARY_AVAILABLE = True
|
|
12
|
+
RICH_AVAILABLE = True
|
|
13
|
+
try:
|
|
14
|
+
import questionary
|
|
15
|
+
except ModuleNotFoundError:
|
|
16
|
+
QUESTIONARY_AVAILABLE = False
|
|
17
|
+
try:
|
|
18
|
+
from rich.console import Console
|
|
19
|
+
from rich.table import Table
|
|
20
|
+
except ModuleNotFoundError:
|
|
21
|
+
RICH_AVAILABLE = False
|
|
22
|
+
|
|
14
23
|
__all__ = ["group"]
|
|
15
24
|
|
|
16
25
|
group = typer.Typer(name="auth", help="Authentication commands for LookML Repository")
|
|
@@ -199,7 +208,7 @@ def list(ctx: typer.Context):
|
|
|
199
208
|
"""
|
|
200
209
|
List all authenticated Looker instances
|
|
201
210
|
"""
|
|
202
|
-
console = Console()
|
|
211
|
+
console = Console() if RICH_AVAILABLE else None
|
|
203
212
|
auth = get_auth(ctx)
|
|
204
213
|
all_instances = auth.list_auth()
|
|
205
214
|
if not all_instances:
|
|
@@ -213,7 +222,10 @@ def list(ctx: typer.Context):
|
|
|
213
222
|
instance[1],
|
|
214
223
|
"Yes" if instance[3] else "No",
|
|
215
224
|
)
|
|
216
|
-
console
|
|
225
|
+
if console:
|
|
226
|
+
console.print(table)
|
|
227
|
+
else:
|
|
228
|
+
print(table)
|
|
217
229
|
|
|
218
230
|
|
|
219
231
|
if __name__ == "__main__":
|
|
@@ -3,10 +3,11 @@ import os
|
|
|
3
3
|
import sqlite3
|
|
4
4
|
import types
|
|
5
5
|
from datetime import datetime, timedelta, timezone
|
|
6
|
-
from typing import List, Self, Tuple, Union
|
|
6
|
+
from typing import List, Self, Tuple, Union, TYPE_CHECKING
|
|
7
7
|
|
|
8
8
|
import requests
|
|
9
|
-
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
import typer
|
|
10
11
|
from looker_sdk.rtl import serialize
|
|
11
12
|
from looker_sdk.rtl.api_settings import ApiSettings, SettingsConfig
|
|
12
13
|
from looker_sdk.rtl.auth_session import AuthSession, CryptoHash, OAuthSession
|
|
@@ -25,7 +26,7 @@ from lkr.logger import logger
|
|
|
25
26
|
__all__ = ["get_auth", "ApiKeyAuthSession", "DbOAuthSession"]
|
|
26
27
|
|
|
27
28
|
|
|
28
|
-
def get_auth(ctx: typer.Context
|
|
29
|
+
def get_auth(ctx: Union["typer.Context", LkrCtxObj]) -> Union["SqlLiteAuth", "ApiKeyAuth"]:
|
|
29
30
|
if isinstance(ctx, LkrCtxObj):
|
|
30
31
|
lkr_ctx = ctx
|
|
31
32
|
else:
|
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
|
+
from lkr.custom_types import LogLevel
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
STRUCT_LOG_AVAILABLE = True
|
|
6
|
+
RICH_AVAILABLE = True
|
|
7
|
+
try:
|
|
8
|
+
import structlog
|
|
9
|
+
except ModuleNotFoundError:
|
|
10
|
+
STRUCT_LOG_AVAILABLE = False
|
|
11
|
+
try:
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
from rich.logging import RichHandler
|
|
14
|
+
from rich.theme import Theme
|
|
15
|
+
except ModuleNotFoundError:
|
|
16
|
+
RICH_AVAILABLE = False
|
|
8
17
|
|
|
9
|
-
from lkr.custom_types import LogLevel
|
|
10
18
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
if STRUCT_LOG_AVAILABLE:
|
|
20
|
+
structlog.configure(
|
|
21
|
+
processors=[
|
|
22
|
+
structlog.processors.TimeStamper(fmt="iso"),
|
|
23
|
+
structlog.processors.JSONRenderer(),
|
|
24
|
+
]
|
|
25
|
+
)
|
|
17
26
|
|
|
18
27
|
# Define a custom theme for our logging
|
|
19
28
|
theme = Theme(
|
|
@@ -24,10 +33,10 @@ theme = Theme(
|
|
|
24
33
|
"logging.level.error": "bold red",
|
|
25
34
|
"logging.level.critical": "bold white on red",
|
|
26
35
|
}
|
|
27
|
-
)
|
|
36
|
+
) if RICH_AVAILABLE else None
|
|
28
37
|
|
|
29
38
|
# Create a console for logging
|
|
30
|
-
console = Console(theme=theme)
|
|
39
|
+
console = Console(theme=theme) if RICH_AVAILABLE else None
|
|
31
40
|
|
|
32
41
|
# Configure the logging handler
|
|
33
42
|
handler = RichHandler(
|
|
@@ -37,7 +46,7 @@ handler = RichHandler(
|
|
|
37
46
|
markup=True,
|
|
38
47
|
rich_tracebacks=True,
|
|
39
48
|
tracebacks_show_locals=True,
|
|
40
|
-
)
|
|
49
|
+
) if RICH_AVAILABLE else None
|
|
41
50
|
|
|
42
51
|
# Get log level from environment variable, defaulting to INFO
|
|
43
52
|
DEFAULT_LOG_LEVEL = "INFO"
|
|
@@ -50,25 +59,27 @@ logging.basicConfig(
|
|
|
50
59
|
), # Fallback to INFO if invalid level
|
|
51
60
|
format="%(message)s",
|
|
52
61
|
datefmt="[%X]",
|
|
53
|
-
handlers=[handler],
|
|
62
|
+
handlers=[handler] if handler else [],
|
|
54
63
|
)
|
|
55
64
|
|
|
56
65
|
# Create a logger for the application
|
|
57
66
|
logger = logging.getLogger("lkr")
|
|
58
|
-
structured_logger = structlog.get_logger("lkr.structured")
|
|
67
|
+
structured_logger = structlog.get_logger("lkr.structured") if STRUCT_LOG_AVAILABLE else None
|
|
59
68
|
|
|
60
69
|
|
|
61
70
|
# Configure the requests_transport logger to only show debug messages when LOG_LEVEL is DEBUG
|
|
62
|
-
requests_logger = logging.getLogger("looker_sdk.rtl.requests_transport")
|
|
63
|
-
if log_level != "DEBUG":
|
|
71
|
+
requests_logger = logging.getLogger("looker_sdk.rtl.requests_transport") if RICH_AVAILABLE else None
|
|
72
|
+
if log_level != "DEBUG" and requests_logger:
|
|
64
73
|
requests_logger.setLevel(logging.WARNING)
|
|
65
74
|
|
|
66
75
|
|
|
67
76
|
def set_log_level(level: LogLevel):
|
|
68
77
|
"""Set the logging level for the application."""
|
|
69
78
|
logger.setLevel(getattr(logging, level.value))
|
|
70
|
-
|
|
79
|
+
if structured_logger:
|
|
80
|
+
structured_logger.setLevel(getattr(logging, level.value))
|
|
71
81
|
# Update requests_transport logger level based on the new level
|
|
72
|
-
requests_logger
|
|
73
|
-
|
|
74
|
-
|
|
82
|
+
if requests_logger:
|
|
83
|
+
requests_logger.setLevel(
|
|
84
|
+
logging.DEBUG if level == LogLevel.DEBUG else logging.WARNING
|
|
85
|
+
)
|
|
@@ -7,9 +7,6 @@ from lkr.auth.main import group as auth_group
|
|
|
7
7
|
from lkr.classes import LkrCtxObj
|
|
8
8
|
from lkr.custom_types import LogLevel
|
|
9
9
|
from lkr.logger import logger
|
|
10
|
-
from lkr.mcp.main import group as mcp_group
|
|
11
|
-
from lkr.observability.main import group as observability_group
|
|
12
|
-
from lkr.tools.main import group as tools_group
|
|
13
10
|
|
|
14
11
|
app = typer.Typer(
|
|
15
12
|
name="lkr",
|
|
@@ -19,10 +16,32 @@ app = typer.Typer(
|
|
|
19
16
|
)
|
|
20
17
|
|
|
21
18
|
app.add_typer(auth_group, name="auth")
|
|
22
|
-
app.add_typer(mcp_group, name="mcp")
|
|
23
|
-
app.add_typer(observability_group, name="observability")
|
|
24
|
-
app.add_typer(tools_group, name="tools")
|
|
25
19
|
|
|
20
|
+
IMPORT_ERROR = None
|
|
21
|
+
|
|
22
|
+
def add_optional_typer_group(app, import_path, group_name, extra_message=None):
|
|
23
|
+
try:
|
|
24
|
+
module_path, attr = import_path.rsplit(".", 1)
|
|
25
|
+
mod = __import__(module_path, fromlist=[attr])
|
|
26
|
+
group = getattr(mod, attr)
|
|
27
|
+
app.add_typer(group, name=group_name)
|
|
28
|
+
except ModuleNotFoundError as import_error:
|
|
29
|
+
@app.command(
|
|
30
|
+
name=group_name,
|
|
31
|
+
add_help_option=False,
|
|
32
|
+
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
33
|
+
)
|
|
34
|
+
def fallback(import_error=import_error):
|
|
35
|
+
msg = f"{group_name} tools (dependencies not available, try installing optional dependencies: lkr-dev-cli\\[{group_name}])"
|
|
36
|
+
if extra_message:
|
|
37
|
+
msg += f" {extra_message}"
|
|
38
|
+
logger.error(msg)
|
|
39
|
+
logger.error(import_error)
|
|
40
|
+
raise typer.Exit(1)
|
|
41
|
+
|
|
42
|
+
add_optional_typer_group(app, "lkr.mcp.main.group", "mcp")
|
|
43
|
+
add_optional_typer_group(app, "lkr.observability.main.group", "observability")
|
|
44
|
+
add_optional_typer_group(app, "lkr.tools.main.group", "tools")
|
|
26
45
|
|
|
27
46
|
@app.callback()
|
|
28
47
|
def callback(
|