glaip-sdk 0.0.6a0__py3-none-any.whl → 0.0.7__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.
- glaip_sdk/_version.py +42 -19
- glaip_sdk/cli/commands/agents.py +17 -26
- glaip_sdk/cli/commands/configure.py +2 -2
- glaip_sdk/cli/commands/mcps.py +2 -4
- glaip_sdk/cli/commands/tools.py +2 -4
- glaip_sdk/cli/display.py +11 -12
- glaip_sdk/cli/utils.py +63 -33
- glaip_sdk/client/agents.py +101 -73
- glaip_sdk/client/base.py +45 -14
- glaip_sdk/client/tools.py +44 -26
- glaip_sdk/models.py +1 -0
- glaip_sdk/utils/client_utils.py +95 -71
- glaip_sdk/utils/import_export.py +3 -1
- glaip_sdk/utils/rendering/renderer/base.py +152 -125
- glaip_sdk/utils/serialization.py +6 -2
- {glaip_sdk-0.0.6a0.dist-info → glaip_sdk-0.0.7.dist-info}/METADATA +1 -1
- {glaip_sdk-0.0.6a0.dist-info → glaip_sdk-0.0.7.dist-info}/RECORD +19 -19
- {glaip_sdk-0.0.6a0.dist-info → glaip_sdk-0.0.7.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.0.6a0.dist-info → glaip_sdk-0.0.7.dist-info}/entry_points.txt +0 -0
glaip_sdk/_version.py
CHANGED
|
@@ -24,28 +24,51 @@ except Exception: # pragma: no cover
|
|
|
24
24
|
_toml = None # type: ignore
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
def
|
|
27
|
+
def _try_get_installed_version() -> str | None:
|
|
28
|
+
"""Try to get version from installed package."""
|
|
28
29
|
try:
|
|
29
30
|
return version("glaip-sdk")
|
|
30
31
|
except PackageNotFoundError:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _try_get_dev_version() -> str | None:
|
|
36
|
+
"""Try to get version from local pyproject.toml for development."""
|
|
37
|
+
if _toml is None:
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
from pathlib import Path
|
|
42
|
+
|
|
43
|
+
here = Path(__file__).resolve()
|
|
44
|
+
root = here.parent.parent # project root (contains pyproject.toml)
|
|
45
|
+
pyproject = root / "pyproject.toml"
|
|
46
|
+
if not pyproject.is_file():
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
data = _toml.loads(pyproject.read_text(encoding="utf-8"))
|
|
50
|
+
ver = data.get("project", {}).get("version") or data.get("tool", {}).get(
|
|
51
|
+
"poetry", {}
|
|
52
|
+
).get("version")
|
|
53
|
+
if isinstance(ver, str) and ver:
|
|
54
|
+
return ver
|
|
55
|
+
except Exception:
|
|
56
|
+
pass
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _get_version() -> str:
|
|
61
|
+
# Try installed version first
|
|
62
|
+
installed_version = _try_get_installed_version()
|
|
63
|
+
if installed_version:
|
|
64
|
+
return installed_version
|
|
65
|
+
|
|
66
|
+
# Try development version
|
|
67
|
+
dev_version = _try_get_dev_version()
|
|
68
|
+
if dev_version:
|
|
69
|
+
return dev_version
|
|
70
|
+
|
|
71
|
+
return "0.0.0.dev0"
|
|
49
72
|
|
|
50
73
|
|
|
51
74
|
__version__ = _get_version()
|
glaip_sdk/cli/commands/agents.py
CHANGED
|
@@ -47,6 +47,7 @@ from glaip_sdk.cli.utils import (
|
|
|
47
47
|
_fuzzy_pick_for_resources,
|
|
48
48
|
build_renderer,
|
|
49
49
|
coerce_to_row,
|
|
50
|
+
detect_export_format,
|
|
50
51
|
get_client,
|
|
51
52
|
get_ctx_value,
|
|
52
53
|
output_flags,
|
|
@@ -180,7 +181,7 @@ def _format_fallback_agent_data(client: Any, agent: Any) -> dict:
|
|
|
180
181
|
result_data = build_resource_result_data(full_agent, fields)
|
|
181
182
|
|
|
182
183
|
# Handle missing instruction
|
|
183
|
-
if
|
|
184
|
+
if result_data.get("instruction") in ["N/A", None, ""]:
|
|
184
185
|
result_data["instruction"] = "-"
|
|
185
186
|
|
|
186
187
|
# Format dates for better display
|
|
@@ -356,18 +357,15 @@ def get(ctx: Any, agent_ref: str, select: int | None, export: str | None) -> Non
|
|
|
356
357
|
)
|
|
357
358
|
|
|
358
359
|
# Handle export option
|
|
359
|
-
if export:
|
|
360
|
+
if export:
|
|
360
361
|
export_path = Path(export)
|
|
361
362
|
# Auto-detect format from file extension
|
|
362
|
-
|
|
363
|
-
detected_format = "yaml"
|
|
364
|
-
else:
|
|
365
|
-
detected_format = "json"
|
|
363
|
+
detected_format = detect_export_format(export_path)
|
|
366
364
|
|
|
367
365
|
# Always export comprehensive data - re-fetch agent with full details
|
|
368
366
|
try:
|
|
369
367
|
agent = client.agents.get_agent_by_id(agent.id)
|
|
370
|
-
except Exception as e:
|
|
368
|
+
except Exception as e:
|
|
371
369
|
handle_rich_output(
|
|
372
370
|
ctx,
|
|
373
371
|
Text(
|
|
@@ -584,8 +582,7 @@ def run(
|
|
|
584
582
|
handle_json_output(ctx, error=Exception(error_msg))
|
|
585
583
|
raise click.ClickException(error_msg)
|
|
586
584
|
except Exception as e:
|
|
587
|
-
|
|
588
|
-
raise click.ClickException(str(e))
|
|
585
|
+
_handle_command_exception(ctx, e)
|
|
589
586
|
|
|
590
587
|
|
|
591
588
|
def _handle_import_file_logic(
|
|
@@ -798,8 +795,8 @@ def _handle_successful_creation(ctx: Any, agent: Any, model: str | None) -> None
|
|
|
798
795
|
handle_rich_output(ctx, display_agent_run_suggestions(agent))
|
|
799
796
|
|
|
800
797
|
|
|
801
|
-
def
|
|
802
|
-
"""Handle exceptions during
|
|
798
|
+
def _handle_command_exception(ctx: Any, e: Exception) -> None:
|
|
799
|
+
"""Handle exceptions during command execution with consistent error handling."""
|
|
803
800
|
if isinstance(e, click.ClickException):
|
|
804
801
|
if get_ctx_value(ctx, "view") == "json":
|
|
805
802
|
handle_json_output(ctx, error=Exception(AGENT_NOT_FOUND_ERROR))
|
|
@@ -811,6 +808,11 @@ def _handle_creation_exception(ctx: Any, e: Exception) -> None:
|
|
|
811
808
|
raise click.ClickException(str(e))
|
|
812
809
|
|
|
813
810
|
|
|
811
|
+
def _handle_creation_exception(ctx: Any, e: Exception) -> None:
|
|
812
|
+
"""Handle exceptions during agent creation."""
|
|
813
|
+
_handle_command_exception(ctx, e)
|
|
814
|
+
|
|
815
|
+
|
|
814
816
|
@agents_group.command()
|
|
815
817
|
@click.option("--name", help="Agent name")
|
|
816
818
|
@click.option("--instruction", help="Agent instruction (prompt)")
|
|
@@ -1089,10 +1091,7 @@ def update(
|
|
|
1089
1091
|
# Re-raise ClickExceptions without additional processing
|
|
1090
1092
|
raise
|
|
1091
1093
|
except Exception as e:
|
|
1092
|
-
|
|
1093
|
-
if get_ctx_value(ctx, "view") != "json":
|
|
1094
|
-
print_api_error(e)
|
|
1095
|
-
raise click.ClickException(str(e))
|
|
1094
|
+
_handle_command_exception(ctx, e)
|
|
1096
1095
|
|
|
1097
1096
|
|
|
1098
1097
|
@agents_group.command()
|
|
@@ -1133,10 +1132,7 @@ def delete(ctx: Any, agent_id: str, yes: bool) -> None:
|
|
|
1133
1132
|
# Re-raise ClickExceptions without additional processing
|
|
1134
1133
|
raise
|
|
1135
1134
|
except Exception as e:
|
|
1136
|
-
|
|
1137
|
-
if get_ctx_value(ctx, "view") != "json":
|
|
1138
|
-
print_api_error(e)
|
|
1139
|
-
raise click.ClickException(str(e))
|
|
1135
|
+
_handle_command_exception(ctx, e)
|
|
1140
1136
|
|
|
1141
1137
|
|
|
1142
1138
|
@agents_group.command()
|
|
@@ -1149,9 +1145,7 @@ def delete(ctx: Any, agent_id: str, yes: bool) -> None:
|
|
|
1149
1145
|
)
|
|
1150
1146
|
@output_flags()
|
|
1151
1147
|
@click.pass_context
|
|
1152
|
-
def sync_langflow(
|
|
1153
|
-
ctx: Any, base_url: str | None, api_key: str | None
|
|
1154
|
-
) -> None: # pragma: no cover - integration-only path
|
|
1148
|
+
def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
|
|
1155
1149
|
"""Sync agents with LangFlow server flows.
|
|
1156
1150
|
|
|
1157
1151
|
This command fetches all flows from the configured LangFlow server and
|
|
@@ -1192,7 +1186,4 @@ def sync_langflow(
|
|
|
1192
1186
|
)
|
|
1193
1187
|
|
|
1194
1188
|
except Exception as e:
|
|
1195
|
-
|
|
1196
|
-
if get_ctx_value(ctx, "view") != "json":
|
|
1197
|
-
print_api_error(e)
|
|
1198
|
-
raise click.ClickException(str(e))
|
|
1189
|
+
_handle_command_exception(ctx, e)
|
|
@@ -47,8 +47,8 @@ def save_config(config: dict[str, Any]) -> None:
|
|
|
47
47
|
# Set secure file permissions
|
|
48
48
|
try:
|
|
49
49
|
os.chmod(CONFIG_FILE, 0o600)
|
|
50
|
-
except Exception:
|
|
51
|
-
pass
|
|
50
|
+
except Exception: # pragma: no cover - platform dependent best effort
|
|
51
|
+
pass
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
@click.group()
|
glaip_sdk/cli/commands/mcps.py
CHANGED
|
@@ -30,6 +30,7 @@ from glaip_sdk.cli.io import (
|
|
|
30
30
|
from glaip_sdk.cli.resolution import resolve_resource_reference
|
|
31
31
|
from glaip_sdk.cli.utils import (
|
|
32
32
|
coerce_to_row,
|
|
33
|
+
detect_export_format,
|
|
33
34
|
get_client,
|
|
34
35
|
get_ctx_value,
|
|
35
36
|
output_flags,
|
|
@@ -178,10 +179,7 @@ def get(ctx: Any, mcp_ref: str, export: str | None) -> None:
|
|
|
178
179
|
if export:
|
|
179
180
|
export_path = Path(export)
|
|
180
181
|
# Auto-detect format from file extension
|
|
181
|
-
|
|
182
|
-
detected_format = "yaml"
|
|
183
|
-
else:
|
|
184
|
-
detected_format = "json"
|
|
182
|
+
detected_format = detect_export_format(export_path)
|
|
185
183
|
|
|
186
184
|
# Always export comprehensive data - re-fetch MCP with full details if needed
|
|
187
185
|
try:
|
glaip_sdk/cli/commands/tools.py
CHANGED
|
@@ -34,6 +34,7 @@ from glaip_sdk.cli.io import (
|
|
|
34
34
|
from glaip_sdk.cli.resolution import resolve_resource_reference
|
|
35
35
|
from glaip_sdk.cli.utils import (
|
|
36
36
|
coerce_to_row,
|
|
37
|
+
detect_export_format,
|
|
37
38
|
get_client,
|
|
38
39
|
get_ctx_value,
|
|
39
40
|
output_flags,
|
|
@@ -328,10 +329,7 @@ def get(ctx: Any, tool_ref: str, select: int | None, export: str | None) -> None
|
|
|
328
329
|
if export:
|
|
329
330
|
export_path = Path(export)
|
|
330
331
|
# Auto-detect format from file extension
|
|
331
|
-
|
|
332
|
-
detected_format = "yaml"
|
|
333
|
-
else:
|
|
334
|
-
detected_format = "json"
|
|
332
|
+
detected_format = detect_export_format(export_path)
|
|
335
333
|
|
|
336
334
|
# Always export comprehensive data - re-fetch tool with full details if needed
|
|
337
335
|
try:
|
glaip_sdk/cli/display.py
CHANGED
|
@@ -134,17 +134,18 @@ _MISSING = object()
|
|
|
134
134
|
def build_resource_result_data(resource: Any, fields: list[str]) -> dict[str, Any]:
|
|
135
135
|
"""Return a normalized mapping of ``fields`` extracted from ``resource``."""
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
137
|
+
result: dict[str, Any] = {}
|
|
138
|
+
for field in fields:
|
|
139
|
+
try:
|
|
140
|
+
value = getattr(resource, field)
|
|
141
|
+
except AttributeError:
|
|
142
|
+
value = _MISSING
|
|
143
|
+
except Exception:
|
|
144
|
+
value = _MISSING
|
|
141
145
|
|
|
146
|
+
result[field] = _normalise_field_value(field, value)
|
|
142
147
|
|
|
143
|
-
|
|
144
|
-
try:
|
|
145
|
-
return getattr(resource, field, _MISSING)
|
|
146
|
-
except Exception:
|
|
147
|
-
return _MISSING
|
|
148
|
+
return result
|
|
148
149
|
|
|
149
150
|
|
|
150
151
|
def _normalise_field_value(field: str, value: Any) -> Any:
|
|
@@ -188,9 +189,7 @@ def _build_success_output_data(data: Any) -> dict[str, Any]:
|
|
|
188
189
|
return data if data is not None else {"success": True}
|
|
189
190
|
|
|
190
191
|
|
|
191
|
-
def handle_json_output(
|
|
192
|
-
ctx: Any, data: Any = None, error: Exception = None
|
|
193
|
-
) -> None: # pragma: no cover - formatting covered via integration tests
|
|
192
|
+
def handle_json_output(ctx: Any, data: Any = None, error: Exception = None) -> None:
|
|
194
193
|
"""Handle JSON output format for CLI commands.
|
|
195
194
|
|
|
196
195
|
Args:
|
glaip_sdk/cli/utils.py
CHANGED
|
@@ -15,6 +15,7 @@ import shutil
|
|
|
15
15
|
import subprocess
|
|
16
16
|
import tempfile
|
|
17
17
|
from collections.abc import Callable
|
|
18
|
+
from pathlib import Path
|
|
18
19
|
from typing import TYPE_CHECKING, Any
|
|
19
20
|
|
|
20
21
|
import click
|
|
@@ -29,15 +30,15 @@ try:
|
|
|
29
30
|
from prompt_toolkit.shortcuts import prompt
|
|
30
31
|
|
|
31
32
|
_HAS_PTK = True
|
|
32
|
-
except Exception:
|
|
33
|
+
except Exception: # pragma: no cover - optional dependency
|
|
33
34
|
_HAS_PTK = False
|
|
34
35
|
|
|
35
36
|
try:
|
|
36
37
|
import questionary
|
|
37
|
-
except Exception:
|
|
38
|
+
except Exception: # pragma: no cover - optional dependency
|
|
38
39
|
questionary = None
|
|
39
40
|
|
|
40
|
-
if TYPE_CHECKING:
|
|
41
|
+
if TYPE_CHECKING: # pragma: no cover - import-only during type checking
|
|
41
42
|
from glaip_sdk import Client
|
|
42
43
|
from glaip_sdk.cli.commands.configure import load_config
|
|
43
44
|
from glaip_sdk.rich_components import AIPPanel, AIPTable
|
|
@@ -100,7 +101,7 @@ def _prepare_pager_env(
|
|
|
100
101
|
|
|
101
102
|
def _render_ansi(
|
|
102
103
|
renderable: Any,
|
|
103
|
-
) -> str:
|
|
104
|
+
) -> str:
|
|
104
105
|
"""Render a Rich renderable to an ANSI string suitable for piping to 'less'."""
|
|
105
106
|
buf = io.StringIO()
|
|
106
107
|
tmp_console = Console(
|
|
@@ -116,7 +117,7 @@ def _render_ansi(
|
|
|
116
117
|
return buf.getvalue()
|
|
117
118
|
|
|
118
119
|
|
|
119
|
-
def _pager_header() -> str:
|
|
120
|
+
def _pager_header() -> str:
|
|
120
121
|
v = (os.getenv("AIP_PAGER_HEADER", "1") or "1").strip().lower()
|
|
121
122
|
if v in {"0", "false", "off"}:
|
|
122
123
|
return ""
|
|
@@ -227,7 +228,7 @@ def _get_view(ctx: Any) -> str:
|
|
|
227
228
|
# ----------------------------- Client config ----------------------------- #
|
|
228
229
|
|
|
229
230
|
|
|
230
|
-
def get_client(ctx: Any) -> Client:
|
|
231
|
+
def get_client(ctx: Any) -> Client: # pragma: no cover
|
|
231
232
|
"""Get configured client from context, env, and config file (ctx > env > file)."""
|
|
232
233
|
from glaip_sdk import Client
|
|
233
234
|
|
|
@@ -433,7 +434,9 @@ class _FuzzyCompleter:
|
|
|
433
434
|
def __init__(self, words: list[str]) -> None:
|
|
434
435
|
self.words = words
|
|
435
436
|
|
|
436
|
-
def get_completions(
|
|
437
|
+
def get_completions(
|
|
438
|
+
self, document: Any, _complete_event: Any
|
|
439
|
+
) -> Any: # pragma: no cover
|
|
437
440
|
word = document.get_word_before_cursor()
|
|
438
441
|
if not word:
|
|
439
442
|
return
|
|
@@ -444,7 +447,7 @@ class _FuzzyCompleter:
|
|
|
444
447
|
if self._fuzzy_match(word_lower, label_lower):
|
|
445
448
|
yield Completion(label, start_position=-len(word))
|
|
446
449
|
|
|
447
|
-
def _fuzzy_match(self, search: str, target: str) -> bool:
|
|
450
|
+
def _fuzzy_match(self, search: str, target: str) -> bool: # pragma: no cover
|
|
448
451
|
"""True fuzzy matching: checks if all characters in search appear in order in target."""
|
|
449
452
|
if not search:
|
|
450
453
|
return True
|
|
@@ -502,47 +505,37 @@ def _fuzzy_pick(
|
|
|
502
505
|
complete_in_thread=True,
|
|
503
506
|
complete_while_typing=True,
|
|
504
507
|
)
|
|
505
|
-
except (KeyboardInterrupt, EOFError):
|
|
508
|
+
except (KeyboardInterrupt, EOFError): # pragma: no cover - user cancelled input
|
|
506
509
|
return None
|
|
507
510
|
|
|
508
511
|
return _perform_fuzzy_search(answer, labels, by_label) if answer else None
|
|
509
512
|
|
|
510
513
|
|
|
511
|
-
def
|
|
512
|
-
"""
|
|
513
|
-
Calculate fuzzy match score.
|
|
514
|
-
Higher score = better match.
|
|
515
|
-
Returns -1 if no match possible.
|
|
516
|
-
"""
|
|
514
|
+
def _is_fuzzy_match(search: str, target: str) -> bool:
|
|
515
|
+
"""Check if search string is a fuzzy match for target."""
|
|
517
516
|
if not search:
|
|
518
|
-
return
|
|
517
|
+
return True
|
|
519
518
|
|
|
520
|
-
# Check if it's a fuzzy match first
|
|
521
519
|
search_idx = 0
|
|
522
520
|
for char in target:
|
|
523
521
|
if search_idx < len(search) and search[search_idx] == char:
|
|
524
522
|
search_idx += 1
|
|
525
523
|
if search_idx == len(search):
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
if search_idx < len(search):
|
|
529
|
-
return -1 # Not a fuzzy match
|
|
524
|
+
return True
|
|
525
|
+
return False
|
|
530
526
|
|
|
531
|
-
# Calculate score based on:
|
|
532
|
-
# 1. Exact substring match gets bonus points
|
|
533
|
-
# 2. Consecutive character matches get bonus points
|
|
534
|
-
# 3. Shorter search terms get bonus points
|
|
535
527
|
|
|
536
|
-
|
|
528
|
+
def _calculate_exact_match_bonus(search: str, target: str) -> int:
|
|
529
|
+
"""Calculate bonus for exact substring matches."""
|
|
530
|
+
return 100 if search.lower() in target.lower() else 0
|
|
537
531
|
|
|
538
|
-
# Exact substring bonus
|
|
539
|
-
if search.lower() in target.lower():
|
|
540
|
-
score += 100
|
|
541
532
|
|
|
542
|
-
|
|
533
|
+
def _calculate_consecutive_bonus(search: str, target: str) -> int:
|
|
534
|
+
"""Calculate bonus for consecutive character matches."""
|
|
543
535
|
consecutive = 0
|
|
544
536
|
max_consecutive = 0
|
|
545
537
|
search_idx = 0
|
|
538
|
+
|
|
546
539
|
for char in target:
|
|
547
540
|
if search_idx < len(search) and search[search_idx] == char:
|
|
548
541
|
consecutive += 1
|
|
@@ -551,10 +544,31 @@ def _fuzzy_score(search: str, target: str) -> int:
|
|
|
551
544
|
else:
|
|
552
545
|
consecutive = 0
|
|
553
546
|
|
|
554
|
-
|
|
547
|
+
return max_consecutive * 10
|
|
548
|
+
|
|
555
549
|
|
|
556
|
-
|
|
557
|
-
|
|
550
|
+
def _calculate_length_bonus(search: str, target: str) -> int:
|
|
551
|
+
"""Calculate bonus for shorter search terms."""
|
|
552
|
+
return (len(target) - len(search)) * 2
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
def _fuzzy_score(search: str, target: str) -> int:
|
|
556
|
+
"""
|
|
557
|
+
Calculate fuzzy match score.
|
|
558
|
+
Higher score = better match.
|
|
559
|
+
Returns -1 if no match possible.
|
|
560
|
+
"""
|
|
561
|
+
if not search:
|
|
562
|
+
return 0
|
|
563
|
+
|
|
564
|
+
if not _is_fuzzy_match(search, target):
|
|
565
|
+
return -1 # Not a fuzzy match
|
|
566
|
+
|
|
567
|
+
# Calculate score based on different factors
|
|
568
|
+
score = 0
|
|
569
|
+
score += _calculate_exact_match_bonus(search, target)
|
|
570
|
+
score += _calculate_consecutive_bonus(search, target)
|
|
571
|
+
score += _calculate_length_bonus(search, target)
|
|
558
572
|
|
|
559
573
|
return score
|
|
560
574
|
|
|
@@ -1222,3 +1236,19 @@ def handle_ambiguous_resource(
|
|
|
1222
1236
|
else:
|
|
1223
1237
|
# Re-raise cancellation exceptions
|
|
1224
1238
|
raise
|
|
1239
|
+
|
|
1240
|
+
|
|
1241
|
+
def detect_export_format(file_path: str | Path) -> str:
|
|
1242
|
+
"""Detect export format from file extension.
|
|
1243
|
+
|
|
1244
|
+
Args:
|
|
1245
|
+
file_path: Path to the export file
|
|
1246
|
+
|
|
1247
|
+
Returns:
|
|
1248
|
+
"yaml" if file extension is .yaml or .yml, "json" otherwise
|
|
1249
|
+
"""
|
|
1250
|
+
path = Path(file_path)
|
|
1251
|
+
if path.suffix.lower() in [".yaml", ".yml"]:
|
|
1252
|
+
return "yaml"
|
|
1253
|
+
else:
|
|
1254
|
+
return "json"
|