gooddata-flexconnect 1.60.1.dev1__tar.gz → 1.60.1.dev2__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.
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/PKG-INFO +4 -4
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/json_schemas/execution-context/execution-context.json +55 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/pyproject.toml +13 -4
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/src/gooddata_flexconnect/__init__.py +5 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/src/gooddata_flexconnect/function/data_source_messages.py +3 -3
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/src/gooddata_flexconnect/function/execution_context.py +147 -21
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/src/gooddata_flexconnect/function/flight_methods.py +4 -7
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/src/gooddata_flexconnect/function/function.py +4 -5
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/src/gooddata_flexconnect/function/function_invocation.py +2 -2
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/src/gooddata_flexconnect/function/function_task.py +4 -4
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/function/conftest.py +6 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/function/test_flex_fun_execution_context.py +65 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/function/testing_funs.py +2 -3
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/json_schemas/test_execution_context_schema.py +106 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/funs/fun1.py +1 -2
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/funs/fun2.py +2 -3
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/funs/fun3.py +2 -3
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/funs/fun4.py +2 -3
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tox.ini +1 -1
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/.gitignore +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/.readthedocs.yaml +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/LICENSE.txt +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/Makefile +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/README.md +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/json_schemas/execution-context/attribute.json +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/json_schemas/execution-context/date-granularity.json +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/json_schemas/execution-context/filter.json +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/json_schemas/execution-context/label-elements/depends-on-date-filter.json +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/json_schemas/execution-context/label-elements/depends-on.json +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/json_schemas/execution-context/label-elements/execution-request.json +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/src/gooddata_flexconnect/function/__init__.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/src/gooddata_flexconnect/function/function_registry.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/src/gooddata_flexconnect/py.typed +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/__init__.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/assert_error_info.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/function/__init__.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/function/test_data_source_messages.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/function/test_registry.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/json_schemas/__init__.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/json_schemas/conftest.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/json_schemas/test_attribute_schema.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/json_schemas/test_depends_on_date_filter_schema.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/json_schemas/test_depends_on_schema.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/json_schemas/test_filter_schema.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/json_schemas/test_label_elements_execution_request_schema.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/__init__.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/conftest.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/funs/__init__.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/test_flexconnect_server.py +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/tls/ca-cert.pem +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/tls/client-cert.pem +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/tls/client-key.pem +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/tls/server-cert.pem +0 -0
- {gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/tls/server-key.pem +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gooddata-flexconnect
|
|
3
|
-
Version: 1.60.1.
|
|
3
|
+
Version: 1.60.1.dev2
|
|
4
4
|
Summary: Build your own data source for GoodData Cloud and GoodData Cloud Native.
|
|
5
|
-
Project-URL: Documentation, https://gooddata-flexconnect.readthedocs.io/en/v1.60.1.
|
|
5
|
+
Project-URL: Documentation, https://gooddata-flexconnect.readthedocs.io/en/v1.60.1.dev2
|
|
6
6
|
Project-URL: Source, https://github.com/gooddata/gooddata-python-sdk
|
|
7
7
|
Author-email: GoodData <support@gooddata.com>
|
|
8
8
|
License-Expression: MIT
|
|
@@ -21,8 +21,8 @@ Classifier: Topic :: Software Development
|
|
|
21
21
|
Classifier: Typing :: Typed
|
|
22
22
|
Requires-Python: >=3.10
|
|
23
23
|
Requires-Dist: dynaconf<4.0.0,>=3.1.11
|
|
24
|
-
Requires-Dist: gooddata-flight-server~=1.60.1.
|
|
25
|
-
Requires-Dist: gooddata-sdk~=1.60.1.
|
|
24
|
+
Requires-Dist: gooddata-flight-server~=1.60.1.dev2
|
|
25
|
+
Requires-Dist: gooddata-sdk~=1.60.1.dev2
|
|
26
26
|
Requires-Dist: orjson<4.0.0,>=3.9.15
|
|
27
27
|
Requires-Dist: pyarrow>=16.1.0
|
|
28
28
|
Requires-Dist: structlog<25.0.0,>=24.0.0
|
|
@@ -52,6 +52,61 @@
|
|
|
52
52
|
"items": {
|
|
53
53
|
"$ref": "filter.json"
|
|
54
54
|
}
|
|
55
|
+
},
|
|
56
|
+
"executionInitiator": {
|
|
57
|
+
"type": "object",
|
|
58
|
+
"description": "Information about what triggered this execution.",
|
|
59
|
+
"required": ["type"],
|
|
60
|
+
"discriminator": {
|
|
61
|
+
"propertyName": "type",
|
|
62
|
+
"mapping": {
|
|
63
|
+
"display": "#/properties/executionInitiator/oneOf/0",
|
|
64
|
+
"adhocExport": "#/properties/executionInitiator/oneOf/1",
|
|
65
|
+
"automation": "#/properties/executionInitiator/oneOf/2",
|
|
66
|
+
"alert": "#/properties/executionInitiator/oneOf/3"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"oneOf": [
|
|
70
|
+
{
|
|
71
|
+
"description": "Execution triggered by displaying data in the UI.",
|
|
72
|
+
"properties": {
|
|
73
|
+
"type": { "const": "display" },
|
|
74
|
+
"dashboardId": { "type": "string" },
|
|
75
|
+
"visualizationId": { "type": "string" },
|
|
76
|
+
"widgetId": { "type": "string" }
|
|
77
|
+
},
|
|
78
|
+
"additionalProperties": false
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"description": "Execution triggered by an ad-hoc export from the UI.",
|
|
82
|
+
"properties": {
|
|
83
|
+
"type": { "const": "adhocExport" },
|
|
84
|
+
"dashboardId": { "type": "string" },
|
|
85
|
+
"visualizationId": { "type": "string" },
|
|
86
|
+
"widgetId": { "type": "string" },
|
|
87
|
+
"exportType": { "type": "string" }
|
|
88
|
+
},
|
|
89
|
+
"additionalProperties": false
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"description": "Execution triggered by an automation.",
|
|
93
|
+
"properties": {
|
|
94
|
+
"type": { "const": "automation" },
|
|
95
|
+
"automationId": { "type": "string" }
|
|
96
|
+
},
|
|
97
|
+
"additionalProperties": false
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"description": "Execution triggered by an alert evaluation.",
|
|
101
|
+
"properties": {
|
|
102
|
+
"type": { "const": "alert" },
|
|
103
|
+
"dashboardId": { "type": "string" },
|
|
104
|
+
"visualizationId": { "type": "string" },
|
|
105
|
+
"widgetId": { "type": "string" }
|
|
106
|
+
},
|
|
107
|
+
"additionalProperties": false
|
|
108
|
+
}
|
|
109
|
+
]
|
|
55
110
|
}
|
|
56
111
|
},
|
|
57
112
|
"allOf": [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# (C) 2025 GoodData Corporation
|
|
2
2
|
[project]
|
|
3
3
|
name = "gooddata-flexconnect"
|
|
4
|
-
version = "1.60.1.
|
|
4
|
+
version = "1.60.1.dev2"
|
|
5
5
|
description = "Build your own data source for GoodData Cloud and GoodData Cloud Native."
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = "MIT"
|
|
@@ -29,8 +29,8 @@ keywords = [
|
|
|
29
29
|
requires-python = ">=3.10"
|
|
30
30
|
dependencies = [
|
|
31
31
|
"dynaconf>=3.1.11,<4.0.0",
|
|
32
|
-
"gooddata-flight-server~=1.60.1.
|
|
33
|
-
"gooddata-sdk~=1.60.1.
|
|
32
|
+
"gooddata-flight-server~=1.60.1.dev2",
|
|
33
|
+
"gooddata-sdk~=1.60.1.dev2",
|
|
34
34
|
"orjson>=3.9.15,<4.0.0",
|
|
35
35
|
"pyarrow>=16.1.0",
|
|
36
36
|
"structlog>=24.0.0,<25.0.0",
|
|
@@ -50,7 +50,7 @@ classifiers = [
|
|
|
50
50
|
]
|
|
51
51
|
|
|
52
52
|
[project.urls]
|
|
53
|
-
Documentation = "https://gooddata-flexconnect.readthedocs.io/en/v1.60.1.
|
|
53
|
+
Documentation = "https://gooddata-flexconnect.readthedocs.io/en/v1.60.1.dev2"
|
|
54
54
|
Source = "https://github.com/gooddata/gooddata-python-sdk"
|
|
55
55
|
|
|
56
56
|
[dependency-groups]
|
|
@@ -67,6 +67,15 @@ allowed-unresolved-imports = ["jsonschema.**", "referencing"]
|
|
|
67
67
|
[tool.hatch.build.targets.wheel]
|
|
68
68
|
packages = ["src/gooddata_flexconnect"]
|
|
69
69
|
|
|
70
|
+
[tool.coverage.run]
|
|
71
|
+
source = ["gooddata_flexconnect"]
|
|
72
|
+
|
|
73
|
+
[tool.coverage.paths]
|
|
74
|
+
source = [
|
|
75
|
+
"src/gooddata_flexconnect",
|
|
76
|
+
"**/site-packages/gooddata_flexconnect",
|
|
77
|
+
]
|
|
78
|
+
|
|
70
79
|
[build-system]
|
|
71
80
|
requires = ["hatchling"]
|
|
72
81
|
build-backend = "hatchling.build"
|
|
@@ -14,6 +14,11 @@ from gooddata_flexconnect.function.execution_context import (
|
|
|
14
14
|
ExecutionContextNegativeAttributeFilter,
|
|
15
15
|
ExecutionContextPositiveAttributeFilter,
|
|
16
16
|
ExecutionContextRelativeDateFilter,
|
|
17
|
+
ExecutionInitiator,
|
|
18
|
+
ExecutionInitiatorAdHocExport,
|
|
19
|
+
ExecutionInitiatorAlert,
|
|
20
|
+
ExecutionInitiatorAutomation,
|
|
21
|
+
ExecutionInitiatorDisplay,
|
|
17
22
|
ExecutionRequest,
|
|
18
23
|
ExecutionType,
|
|
19
24
|
LabelElementsExecutionRequest,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# (C) 2025 GoodData Corporation
|
|
2
2
|
from collections.abc import Iterable
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
5
5
|
|
|
6
6
|
import orjson
|
|
7
7
|
import pyarrow
|
|
@@ -33,7 +33,7 @@ class DataSourceMessage:
|
|
|
33
33
|
Type of the message, currently free-form, we might define some enum for these in the future.
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
|
-
data:
|
|
36
|
+
data: Any | None = None
|
|
37
37
|
"""
|
|
38
38
|
Optional message-specific data. This can be anything that can be JSON-serialized.
|
|
39
39
|
Try to keep this as small as possible: the backend has a quite strict size limit on the messages.
|
|
@@ -47,7 +47,7 @@ class DataSourceMessage:
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
def add_data_source_messages_metadata(
|
|
50
|
-
data_source_messages: Iterable[DataSourceMessage], original_metadata:
|
|
50
|
+
data_source_messages: Iterable[DataSourceMessage], original_metadata: dict | None = None
|
|
51
51
|
) -> dict[bytes, bytes]:
|
|
52
52
|
"""
|
|
53
53
|
Given a list of DataSourceMessages, creates a PyArrow-compatible metadata dictionary.
|
|
@@ -21,13 +21,13 @@ TInput = TypeVar("TInput")
|
|
|
21
21
|
TResult = TypeVar("TResult")
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
def none_safe(func: Callable[[TInput], TResult]) -> Callable[[
|
|
24
|
+
def none_safe(func: Callable[[TInput], TResult]) -> Callable[[TInput | None], TResult | None]:
|
|
25
25
|
"""
|
|
26
26
|
Decorator that makes the unary function safe for None input.
|
|
27
27
|
If the only argument is None, the function returns None.
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
|
-
def wrapper(arg:
|
|
30
|
+
def wrapper(arg: TInput | None) -> TResult | None:
|
|
31
31
|
if arg is None:
|
|
32
32
|
return None
|
|
33
33
|
return func(arg)
|
|
@@ -114,18 +114,18 @@ class ExecutionContextAttribute:
|
|
|
114
114
|
Title of the particular label used.
|
|
115
115
|
"""
|
|
116
116
|
|
|
117
|
-
date_granularity:
|
|
117
|
+
date_granularity: str | None
|
|
118
118
|
"""
|
|
119
119
|
Date granularity of the attribute if it is a date attribute.
|
|
120
120
|
"""
|
|
121
121
|
|
|
122
|
-
sorting:
|
|
122
|
+
sorting: ExecutionContextAttributeSorting | None
|
|
123
123
|
"""
|
|
124
124
|
Sorting of the attribute. If not present, the attribute is not sorted.
|
|
125
125
|
"""
|
|
126
126
|
|
|
127
127
|
@staticmethod
|
|
128
|
-
def from_dict(d:
|
|
128
|
+
def from_dict(d: dict | None) -> Optional["ExecutionContextAttribute"]:
|
|
129
129
|
"""
|
|
130
130
|
Create ExecutionContextAttribute from a dictionary.
|
|
131
131
|
:param d: the dictionary to parse
|
|
@@ -153,7 +153,7 @@ class ExecutionContextPositiveAttributeFilter:
|
|
|
153
153
|
Identifier of the label used.
|
|
154
154
|
"""
|
|
155
155
|
|
|
156
|
-
values: list[
|
|
156
|
+
values: list[str | None]
|
|
157
157
|
"""
|
|
158
158
|
Values of the filter.
|
|
159
159
|
"""
|
|
@@ -170,7 +170,7 @@ class ExecutionContextNegativeAttributeFilter:
|
|
|
170
170
|
Identifier of the label used.
|
|
171
171
|
"""
|
|
172
172
|
|
|
173
|
-
values: list[
|
|
173
|
+
values: list[str | None]
|
|
174
174
|
"""
|
|
175
175
|
Values of the filter.
|
|
176
176
|
"""
|
|
@@ -366,17 +366,17 @@ class LabelElementsExecutionRequest:
|
|
|
366
366
|
The label to get the elements for.
|
|
367
367
|
"""
|
|
368
368
|
|
|
369
|
-
offset:
|
|
369
|
+
offset: int | None
|
|
370
370
|
"""
|
|
371
371
|
The number of elements to skip before returning.
|
|
372
372
|
"""
|
|
373
373
|
|
|
374
|
-
limit:
|
|
374
|
+
limit: int | None
|
|
375
375
|
"""
|
|
376
376
|
The maximum number of elements to return.
|
|
377
377
|
"""
|
|
378
378
|
|
|
379
|
-
exclude_primary_label:
|
|
379
|
+
exclude_primary_label: bool | None
|
|
380
380
|
"""
|
|
381
381
|
Excludes items from the result that differ only by primary label
|
|
382
382
|
|
|
@@ -384,33 +384,33 @@ class LabelElementsExecutionRequest:
|
|
|
384
384
|
* true - return items with distinct requested label
|
|
385
385
|
"""
|
|
386
386
|
|
|
387
|
-
exact_filter:
|
|
387
|
+
exact_filter: list[str] | None
|
|
388
388
|
"""
|
|
389
389
|
Exact values to filter the elements by.
|
|
390
390
|
"""
|
|
391
391
|
|
|
392
|
-
pattern_filter:
|
|
392
|
+
pattern_filter: str | None
|
|
393
393
|
"""
|
|
394
394
|
Filter the elements by a pattern. The pattern is matched against the element values in a case-insensitive way.
|
|
395
395
|
"""
|
|
396
396
|
|
|
397
|
-
complement_filter:
|
|
397
|
+
complement_filter: bool | None
|
|
398
398
|
"""
|
|
399
399
|
Whether to invert the effects of exact_filter amd pattern_filter.
|
|
400
400
|
"""
|
|
401
401
|
|
|
402
|
-
depends_on:
|
|
402
|
+
depends_on: list[DependsOn] | None
|
|
403
403
|
"""
|
|
404
404
|
Other labels or date filters that should be used to limit the elements.
|
|
405
405
|
"""
|
|
406
406
|
|
|
407
|
-
filter_by:
|
|
407
|
+
filter_by: CatalogFilterBy | None
|
|
408
408
|
"""
|
|
409
409
|
Which label is used for filtering - primary or requested.
|
|
410
410
|
If omitted the server will use the default value of "REQUESTED".
|
|
411
411
|
"""
|
|
412
412
|
|
|
413
|
-
validate_by:
|
|
413
|
+
validate_by: list[CatalogValidateByItem] | None
|
|
414
414
|
"""
|
|
415
415
|
Other metrics, attributes, labels or facts used to validate the elements.
|
|
416
416
|
"""
|
|
@@ -436,6 +436,126 @@ class LabelElementsExecutionRequest:
|
|
|
436
436
|
)
|
|
437
437
|
|
|
438
438
|
|
|
439
|
+
@dataclass
|
|
440
|
+
class ExecutionInitiatorDisplay:
|
|
441
|
+
"""
|
|
442
|
+
Information about an execution being run in order to display the data in the UI.
|
|
443
|
+
"""
|
|
444
|
+
|
|
445
|
+
dashboard_id: str | None
|
|
446
|
+
"""
|
|
447
|
+
The id of the dashboard the execution was run as a part of.
|
|
448
|
+
"""
|
|
449
|
+
|
|
450
|
+
visualization_id: str | None
|
|
451
|
+
"""
|
|
452
|
+
The id of the visualization the execution was run as a part of.
|
|
453
|
+
"""
|
|
454
|
+
|
|
455
|
+
widget_id: str | None
|
|
456
|
+
"""
|
|
457
|
+
The id of the widget the execution was run as a part of.
|
|
458
|
+
"""
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
@dataclass
|
|
462
|
+
class ExecutionInitiatorAdHocExport:
|
|
463
|
+
"""
|
|
464
|
+
Information about an execution being run in order to export the data by a user in the UI.
|
|
465
|
+
"""
|
|
466
|
+
|
|
467
|
+
dashboard_id: str | None
|
|
468
|
+
"""
|
|
469
|
+
The id of the dashboard the execution was run as a part of.
|
|
470
|
+
"""
|
|
471
|
+
|
|
472
|
+
visualization_id: str | None
|
|
473
|
+
"""
|
|
474
|
+
The id of the visualization the execution was run as a part of.
|
|
475
|
+
"""
|
|
476
|
+
|
|
477
|
+
widget_id: str | None
|
|
478
|
+
"""
|
|
479
|
+
The id of the widget the execution was run as a part of.
|
|
480
|
+
"""
|
|
481
|
+
|
|
482
|
+
export_type: str | None
|
|
483
|
+
"""
|
|
484
|
+
The type of the exported file (CSV, RAW_CSV, etc.).
|
|
485
|
+
"""
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
@dataclass
|
|
489
|
+
class ExecutionInitiatorAutomation:
|
|
490
|
+
"""
|
|
491
|
+
Information about an execution being run because of an automation.
|
|
492
|
+
"""
|
|
493
|
+
|
|
494
|
+
automation_id: str | None
|
|
495
|
+
"""
|
|
496
|
+
The id of the automation initiating this execution.
|
|
497
|
+
"""
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
@dataclass
|
|
501
|
+
class ExecutionInitiatorAlert:
|
|
502
|
+
"""
|
|
503
|
+
Information about an execution being run in order to evaluate an alert.
|
|
504
|
+
"""
|
|
505
|
+
|
|
506
|
+
dashboard_id: str | None
|
|
507
|
+
"""
|
|
508
|
+
The id of the dashboard the execution was run as a part of.
|
|
509
|
+
"""
|
|
510
|
+
|
|
511
|
+
visualization_id: str | None
|
|
512
|
+
"""
|
|
513
|
+
The id of the visualization the execution was run as a part of.
|
|
514
|
+
"""
|
|
515
|
+
|
|
516
|
+
widget_id: str | None
|
|
517
|
+
"""
|
|
518
|
+
The id of the widget the execution was run as a part of.
|
|
519
|
+
"""
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
ExecutionInitiator: TypeAlias = Union[
|
|
523
|
+
ExecutionInitiatorDisplay,
|
|
524
|
+
ExecutionInitiatorAdHocExport,
|
|
525
|
+
ExecutionInitiatorAutomation,
|
|
526
|
+
ExecutionInitiatorAlert,
|
|
527
|
+
]
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
@none_safe
|
|
531
|
+
def _dict_to_execution_initiator(d: dict) -> ExecutionInitiator:
|
|
532
|
+
initiator_type = d.get("type")
|
|
533
|
+
if initiator_type == "display":
|
|
534
|
+
return ExecutionInitiatorDisplay(
|
|
535
|
+
dashboard_id=d.get("dashboardId"),
|
|
536
|
+
visualization_id=d.get("visualizationId"),
|
|
537
|
+
widget_id=d.get("widgetId"),
|
|
538
|
+
)
|
|
539
|
+
if initiator_type == "adhocExport":
|
|
540
|
+
return ExecutionInitiatorAdHocExport(
|
|
541
|
+
export_type=d.get("exportType"),
|
|
542
|
+
dashboard_id=d.get("dashboardId"),
|
|
543
|
+
visualization_id=d.get("visualizationId"),
|
|
544
|
+
widget_id=d.get("widgetId"),
|
|
545
|
+
)
|
|
546
|
+
if initiator_type == "automation":
|
|
547
|
+
return ExecutionInitiatorAutomation(
|
|
548
|
+
automation_id=d.get("automationId"),
|
|
549
|
+
)
|
|
550
|
+
if initiator_type == "alert":
|
|
551
|
+
return ExecutionInitiatorAlert(
|
|
552
|
+
dashboard_id=d.get("dashboardId"),
|
|
553
|
+
visualization_id=d.get("visualizationId"),
|
|
554
|
+
widget_id=d.get("widgetId"),
|
|
555
|
+
)
|
|
556
|
+
raise ValueError(f"Unsupported execution initiator type: {initiator_type}")
|
|
557
|
+
|
|
558
|
+
|
|
439
559
|
def _dict_to_filter(d: dict) -> ExecutionContextFilter:
|
|
440
560
|
filter_type = d.get("filterType")
|
|
441
561
|
if filter_type == "positiveAttributeFilter":
|
|
@@ -504,18 +624,18 @@ class ExecutionContext:
|
|
|
504
624
|
The ID of the user that invoked the FlexConnect function.
|
|
505
625
|
"""
|
|
506
626
|
|
|
507
|
-
timestamp:
|
|
627
|
+
timestamp: str | None
|
|
508
628
|
"""
|
|
509
629
|
The timestamp of the execution used as "now" in date filters.
|
|
510
630
|
For example 2020-06-03T10:15:30+01:00.
|
|
511
631
|
"""
|
|
512
632
|
|
|
513
|
-
timezone:
|
|
633
|
+
timezone: str | None
|
|
514
634
|
"""
|
|
515
635
|
The timezone of the execution.
|
|
516
636
|
"""
|
|
517
637
|
|
|
518
|
-
week_start:
|
|
638
|
+
week_start: str | None
|
|
519
639
|
"""
|
|
520
640
|
The start of the week. Either "monday" or "sunday".
|
|
521
641
|
"""
|
|
@@ -530,18 +650,23 @@ class ExecutionContext:
|
|
|
530
650
|
All the attribute and date filters that are part of the execution request.
|
|
531
651
|
"""
|
|
532
652
|
|
|
533
|
-
report_execution_request:
|
|
653
|
+
report_execution_request: ReportExecutionRequest | None
|
|
534
654
|
"""
|
|
535
655
|
The report execution request that the FlexConnect function should process.
|
|
536
656
|
Only present if the execution type is "REPORT".
|
|
537
657
|
"""
|
|
538
658
|
|
|
539
|
-
label_elements_execution_request:
|
|
659
|
+
label_elements_execution_request: LabelElementsExecutionRequest | None
|
|
540
660
|
"""
|
|
541
661
|
The label elements execution request that the FlexConnect function should process.
|
|
542
662
|
Only present if the execution type is "LABEL_ELEMENTS".
|
|
543
663
|
"""
|
|
544
664
|
|
|
665
|
+
execution_initiator: ExecutionInitiator | None
|
|
666
|
+
"""
|
|
667
|
+
Information about what triggered this execution (e.g. display, export, automation, alert).
|
|
668
|
+
"""
|
|
669
|
+
|
|
545
670
|
@staticmethod
|
|
546
671
|
@none_safe
|
|
547
672
|
def from_dict(d: dict) -> "ExecutionContext":
|
|
@@ -563,6 +688,7 @@ class ExecutionContext:
|
|
|
563
688
|
),
|
|
564
689
|
attributes=_dict_to_attributes(d.get("attributes", [])),
|
|
565
690
|
filters=_dict_to_filters(d.get("filters", [])),
|
|
691
|
+
execution_initiator=_dict_to_execution_initiator(d.get("executionInitiator")),
|
|
566
692
|
)
|
|
567
693
|
|
|
568
694
|
@staticmethod
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# (C) 2024 GoodData Corporation
|
|
2
2
|
import time
|
|
3
3
|
from collections.abc import Generator
|
|
4
|
-
from typing import Optional
|
|
5
4
|
|
|
6
5
|
import orjson
|
|
7
6
|
import pyarrow.flight
|
|
@@ -59,7 +58,7 @@ class _FlexConnectServerMethods(FlightServerMethods):
|
|
|
59
58
|
self._poll_interval = poll_interval_ms / 1000
|
|
60
59
|
|
|
61
60
|
@staticmethod
|
|
62
|
-
def _create_descriptor(fun_name: str, metadata:
|
|
61
|
+
def _create_descriptor(fun_name: str, metadata: dict | None) -> pyarrow.flight.FlightDescriptor:
|
|
63
62
|
cmd = {
|
|
64
63
|
"functionName": fun_name,
|
|
65
64
|
"metadata": metadata,
|
|
@@ -97,9 +96,7 @@ class _FlexConnectServerMethods(FlightServerMethods):
|
|
|
97
96
|
cmd=submit_invocation.command,
|
|
98
97
|
)
|
|
99
98
|
|
|
100
|
-
def _prepare_flight_info(
|
|
101
|
-
self, task_id: str, task_result: Optional[TaskExecutionResult]
|
|
102
|
-
) -> pyarrow.flight.FlightInfo:
|
|
99
|
+
def _prepare_flight_info(self, task_id: str, task_result: TaskExecutionResult | None) -> pyarrow.flight.FlightInfo:
|
|
103
100
|
if task_result is None:
|
|
104
101
|
raise ErrorInfo.for_reason(
|
|
105
102
|
ErrorCode.BAD_ARGUMENT, f"Task with id '{task_id}' does not exist."
|
|
@@ -142,7 +139,7 @@ class _FlexConnectServerMethods(FlightServerMethods):
|
|
|
142
139
|
structlog.contextvars.bind_contextvars(peer=context.peer())
|
|
143
140
|
invocation = extract_submit_invocation_from_descriptor(descriptor)
|
|
144
141
|
|
|
145
|
-
task:
|
|
142
|
+
task: FlexConnectFunctionTask | None = None
|
|
146
143
|
|
|
147
144
|
try:
|
|
148
145
|
task = self._prepare_task(context, invocation)
|
|
@@ -192,7 +189,7 @@ class _FlexConnectServerMethods(FlightServerMethods):
|
|
|
192
189
|
invocation = extract_pollable_invocation_from_descriptor(descriptor)
|
|
193
190
|
|
|
194
191
|
task_id: str
|
|
195
|
-
fun_name:
|
|
192
|
+
fun_name: str | None = None
|
|
196
193
|
|
|
197
194
|
if isinstance(invocation, CancelInvocation):
|
|
198
195
|
# cancel the given task and raise cancellation exception
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# (C) 2024 GoodData Corporation
|
|
2
2
|
import abc
|
|
3
|
-
from typing import Optional
|
|
4
3
|
|
|
5
4
|
import pyarrow
|
|
6
5
|
from gooddata_flight_server import ArrowData, ServerContext
|
|
@@ -37,17 +36,17 @@ class FlexConnectFunction(abc.ABC):
|
|
|
37
36
|
for every call using the `create` method.
|
|
38
37
|
"""
|
|
39
38
|
|
|
40
|
-
Name:
|
|
39
|
+
Name: str | None = None
|
|
41
40
|
"""
|
|
42
41
|
Function MUST define a unique name
|
|
43
42
|
"""
|
|
44
43
|
|
|
45
|
-
Schema:
|
|
44
|
+
Schema: pyarrow.Schema | None = None
|
|
46
45
|
"""
|
|
47
46
|
Function MUST define schema describing its data.
|
|
48
47
|
"""
|
|
49
48
|
|
|
50
|
-
Metadata:
|
|
49
|
+
Metadata: dict | None = None
|
|
51
50
|
"""
|
|
52
51
|
Function MAY provide additional metadata about themselves. These then
|
|
53
52
|
influence how the function is used by and called from GoodData Cloud & FlexQuery.
|
|
@@ -79,7 +78,7 @@ class FlexConnectFunction(abc.ABC):
|
|
|
79
78
|
def call(
|
|
80
79
|
self,
|
|
81
80
|
parameters: dict,
|
|
82
|
-
columns:
|
|
81
|
+
columns: tuple[str, ...] | None,
|
|
83
82
|
headers: dict[str, list[str]],
|
|
84
83
|
) -> ArrowData:
|
|
85
84
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# (C) 2025 GoodData Corporation
|
|
2
2
|
from dataclasses import dataclass
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Union
|
|
4
4
|
|
|
5
5
|
import orjson
|
|
6
6
|
import pyarrow.flight
|
|
@@ -46,7 +46,7 @@ class SubmitInvocation:
|
|
|
46
46
|
Parameters to pass to the FlexConnect function.
|
|
47
47
|
"""
|
|
48
48
|
|
|
49
|
-
columns:
|
|
49
|
+
columns: tuple[str, ...] | None
|
|
50
50
|
"""
|
|
51
51
|
Columns to get from the FlexConnect function result.
|
|
52
52
|
This may be used for column trimming by the function: the function must return at least those columns.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# (C) 2024 GoodData Corporation
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Union
|
|
3
3
|
|
|
4
4
|
import structlog
|
|
5
5
|
from gooddata_flight_server import FlightDataTaskResult, Task, TaskError, TaskResult
|
|
@@ -16,11 +16,11 @@ class FlexConnectFunctionTask(Task):
|
|
|
16
16
|
self,
|
|
17
17
|
fun: FlexConnectFunction,
|
|
18
18
|
parameters: dict,
|
|
19
|
-
columns:
|
|
19
|
+
columns: tuple[str, ...] | None,
|
|
20
20
|
headers: dict[str, list[str]],
|
|
21
21
|
cmd: bytes,
|
|
22
22
|
cancellable: bool = True,
|
|
23
|
-
task_id:
|
|
23
|
+
task_id: str | None = None,
|
|
24
24
|
):
|
|
25
25
|
super().__init__(cmd, cancellable, task_id)
|
|
26
26
|
|
|
@@ -32,7 +32,7 @@ class FlexConnectFunctionTask(Task):
|
|
|
32
32
|
_LOGGER.info("flexconnect_task_created", fun=fun.Name, task_id=self._task_id)
|
|
33
33
|
|
|
34
34
|
@property
|
|
35
|
-
def fun_name(self) ->
|
|
35
|
+
def fun_name(self) -> str | None:
|
|
36
36
|
return self._fun.Name
|
|
37
37
|
|
|
38
38
|
def run(self) -> Union[TaskResult, TaskError]:
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/function/conftest.py
RENAMED
|
@@ -88,6 +88,12 @@ def sample_report_execution_context_dict():
|
|
|
88
88
|
}
|
|
89
89
|
],
|
|
90
90
|
"filters": [{"filterType": "negativeAttributeFilter", "labelIdentifier": "attribute1", "values": ["id1"]}],
|
|
91
|
+
"executionInitiator": {
|
|
92
|
+
"type": "display",
|
|
93
|
+
"dashboardId": "b2f2d436-9831-4fe0-81df-8c59fd33242b",
|
|
94
|
+
"visualizationId": "bf21d8ec-742c-48d7-8100-80663b43622b",
|
|
95
|
+
"widgetId": "453844a7-4aa8-4456-be23-ac62b9b3b98a",
|
|
96
|
+
},
|
|
91
97
|
}
|
|
92
98
|
|
|
93
99
|
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
# (C) 2024 GoodData Corporation
|
|
2
|
+
import pytest
|
|
2
3
|
from gooddata_flexconnect.function.execution_context import (
|
|
3
4
|
ExecutionContext,
|
|
4
5
|
ExecutionContextAttribute,
|
|
5
6
|
ExecutionContextNegativeAttributeFilter,
|
|
7
|
+
ExecutionInitiatorAdHocExport,
|
|
8
|
+
ExecutionInitiatorAlert,
|
|
9
|
+
ExecutionInitiatorAutomation,
|
|
10
|
+
ExecutionInitiatorDisplay,
|
|
6
11
|
ExecutionType,
|
|
12
|
+
_dict_to_execution_initiator,
|
|
7
13
|
)
|
|
8
14
|
from gooddata_sdk import (
|
|
9
15
|
Attribute,
|
|
@@ -35,6 +41,12 @@ def test_report_execution_context_deser(sample_report_execution_context_dict):
|
|
|
35
41
|
assert isinstance(deserialized.attributes[0], ExecutionContextAttribute)
|
|
36
42
|
assert isinstance(deserialized.filters[0], ExecutionContextNegativeAttributeFilter)
|
|
37
43
|
|
|
44
|
+
assert deserialized.execution_initiator is not None
|
|
45
|
+
assert isinstance(deserialized.execution_initiator, ExecutionInitiatorDisplay)
|
|
46
|
+
assert deserialized.execution_initiator.dashboard_id == "b2f2d436-9831-4fe0-81df-8c59fd33242b"
|
|
47
|
+
assert deserialized.execution_initiator.visualization_id == "bf21d8ec-742c-48d7-8100-80663b43622b"
|
|
48
|
+
assert deserialized.execution_initiator.widget_id == "453844a7-4aa8-4456-be23-ac62b9b3b98a"
|
|
49
|
+
|
|
38
50
|
|
|
39
51
|
def test_label_elements_execution_context_deser(sample_label_execution_context_dict):
|
|
40
52
|
"""
|
|
@@ -58,3 +70,56 @@ def test_label_elements_execution_context_deser(sample_label_execution_context_d
|
|
|
58
70
|
|
|
59
71
|
assert isinstance(deserialized.attributes[0], ExecutionContextAttribute)
|
|
60
72
|
assert isinstance(deserialized.filters[0], ExecutionContextNegativeAttributeFilter)
|
|
73
|
+
|
|
74
|
+
assert deserialized.execution_initiator is None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@pytest.mark.parametrize(
|
|
78
|
+
"initiator_dict, expected_type",
|
|
79
|
+
[
|
|
80
|
+
(
|
|
81
|
+
{
|
|
82
|
+
"type": "display",
|
|
83
|
+
"dashboardId": "d1",
|
|
84
|
+
"visualizationId": "v1",
|
|
85
|
+
"widgetId": "w1",
|
|
86
|
+
},
|
|
87
|
+
ExecutionInitiatorDisplay,
|
|
88
|
+
),
|
|
89
|
+
(
|
|
90
|
+
{
|
|
91
|
+
"type": "adhocExport",
|
|
92
|
+
"dashboardId": "d1",
|
|
93
|
+
"visualizationId": "v1",
|
|
94
|
+
"widgetId": "w1",
|
|
95
|
+
"exportType": "CSV",
|
|
96
|
+
},
|
|
97
|
+
ExecutionInitiatorAdHocExport,
|
|
98
|
+
),
|
|
99
|
+
(
|
|
100
|
+
{
|
|
101
|
+
"type": "automation",
|
|
102
|
+
"automationId": "a1",
|
|
103
|
+
},
|
|
104
|
+
ExecutionInitiatorAutomation,
|
|
105
|
+
),
|
|
106
|
+
(
|
|
107
|
+
{
|
|
108
|
+
"type": "alert",
|
|
109
|
+
"dashboardId": "d1",
|
|
110
|
+
"visualizationId": "v1",
|
|
111
|
+
"widgetId": "w1",
|
|
112
|
+
},
|
|
113
|
+
ExecutionInitiatorAlert,
|
|
114
|
+
),
|
|
115
|
+
],
|
|
116
|
+
ids=["display", "adhocExport", "automation", "alert"],
|
|
117
|
+
)
|
|
118
|
+
def test_execution_initiator_deser(initiator_dict, expected_type):
|
|
119
|
+
result = _dict_to_execution_initiator(initiator_dict)
|
|
120
|
+
assert isinstance(result, expected_type)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def test_execution_initiator_unknown_type():
|
|
124
|
+
with pytest.raises(ValueError, match="Unsupported execution initiator type"):
|
|
125
|
+
_dict_to_execution_initiator({"type": "unknown"})
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/function/testing_funs.py
RENAMED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# (C) 2024 GoodData Corporation
|
|
2
|
-
from typing import Optional
|
|
3
2
|
|
|
4
3
|
import pyarrow
|
|
5
4
|
from gooddata_flexconnect.function.function import FlexConnectFunction
|
|
@@ -13,7 +12,7 @@ class Fun1(FlexConnectFunction):
|
|
|
13
12
|
def call(
|
|
14
13
|
self,
|
|
15
14
|
parameters: dict,
|
|
16
|
-
columns:
|
|
15
|
+
columns: tuple[str, ...] | None,
|
|
17
16
|
headers: dict[str, list[str]],
|
|
18
17
|
) -> ArrowData:
|
|
19
18
|
pass
|
|
@@ -28,7 +27,7 @@ class Fun2(FlexConnectFunction):
|
|
|
28
27
|
def call(
|
|
29
28
|
self,
|
|
30
29
|
parameters: dict,
|
|
31
|
-
columns:
|
|
30
|
+
columns: tuple[str, ...] | None,
|
|
32
31
|
headers: dict[str, list[str]],
|
|
33
32
|
) -> ArrowData:
|
|
34
33
|
pass
|
|
@@ -16,6 +16,69 @@ from jsonschema.exceptions import ValidationError
|
|
|
16
16
|
"filters": [],
|
|
17
17
|
"reportExecutionRequest": {},
|
|
18
18
|
},
|
|
19
|
+
# REPORT with executionInitiator display
|
|
20
|
+
{
|
|
21
|
+
"executionType": "REPORT",
|
|
22
|
+
"organizationId": "org1",
|
|
23
|
+
"workspaceId": "ws1",
|
|
24
|
+
"userId": "user1",
|
|
25
|
+
"attributes": [],
|
|
26
|
+
"filters": [],
|
|
27
|
+
"reportExecutionRequest": {},
|
|
28
|
+
"executionInitiator": {
|
|
29
|
+
"type": "display",
|
|
30
|
+
"dashboardId": "d1",
|
|
31
|
+
"visualizationId": "v1",
|
|
32
|
+
"widgetId": "w1",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
# REPORT with executionInitiator adhocExport
|
|
36
|
+
{
|
|
37
|
+
"executionType": "REPORT",
|
|
38
|
+
"organizationId": "org1",
|
|
39
|
+
"workspaceId": "ws1",
|
|
40
|
+
"userId": "user1",
|
|
41
|
+
"attributes": [],
|
|
42
|
+
"filters": [],
|
|
43
|
+
"reportExecutionRequest": {},
|
|
44
|
+
"executionInitiator": {
|
|
45
|
+
"type": "adhocExport",
|
|
46
|
+
"dashboardId": "d1",
|
|
47
|
+
"visualizationId": "v1",
|
|
48
|
+
"widgetId": "w1",
|
|
49
|
+
"exportType": "CSV",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
# REPORT with executionInitiator automation
|
|
53
|
+
{
|
|
54
|
+
"executionType": "REPORT",
|
|
55
|
+
"organizationId": "org1",
|
|
56
|
+
"workspaceId": "ws1",
|
|
57
|
+
"userId": "user1",
|
|
58
|
+
"attributes": [],
|
|
59
|
+
"filters": [],
|
|
60
|
+
"reportExecutionRequest": {},
|
|
61
|
+
"executionInitiator": {
|
|
62
|
+
"type": "automation",
|
|
63
|
+
"automationId": "a1",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
# REPORT with executionInitiator alert
|
|
67
|
+
{
|
|
68
|
+
"executionType": "REPORT",
|
|
69
|
+
"organizationId": "org1",
|
|
70
|
+
"workspaceId": "ws1",
|
|
71
|
+
"userId": "user1",
|
|
72
|
+
"attributes": [],
|
|
73
|
+
"filters": [],
|
|
74
|
+
"reportExecutionRequest": {},
|
|
75
|
+
"executionInitiator": {
|
|
76
|
+
"type": "alert",
|
|
77
|
+
"dashboardId": "d1",
|
|
78
|
+
"visualizationId": "v1",
|
|
79
|
+
"widgetId": "w1",
|
|
80
|
+
},
|
|
81
|
+
},
|
|
19
82
|
# minimal valid schema for LABEL_ELEMENTS execution type
|
|
20
83
|
{
|
|
21
84
|
"executionType": "LABEL_ELEMENTS",
|
|
@@ -110,6 +173,49 @@ def test_valid_execution_context_schema(value, get_validator):
|
|
|
110
173
|
"filters": [],
|
|
111
174
|
"labelElementsExecutionRequest": {"label": "label2"},
|
|
112
175
|
},
|
|
176
|
+
# invalid executionInitiator type
|
|
177
|
+
{
|
|
178
|
+
"executionType": "REPORT",
|
|
179
|
+
"organizationId": "org1",
|
|
180
|
+
"workspaceId": "ws1",
|
|
181
|
+
"userId": "user1",
|
|
182
|
+
"attributes": [],
|
|
183
|
+
"filters": [],
|
|
184
|
+
"reportExecutionRequest": {},
|
|
185
|
+
"executionInitiator": {
|
|
186
|
+
"type": "INVALID",
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
# automation initiator must not contain dashboardId
|
|
190
|
+
{
|
|
191
|
+
"executionType": "REPORT",
|
|
192
|
+
"organizationId": "org1",
|
|
193
|
+
"workspaceId": "ws1",
|
|
194
|
+
"userId": "user1",
|
|
195
|
+
"attributes": [],
|
|
196
|
+
"filters": [],
|
|
197
|
+
"reportExecutionRequest": {},
|
|
198
|
+
"executionInitiator": {
|
|
199
|
+
"type": "automation",
|
|
200
|
+
"automationId": "a1",
|
|
201
|
+
"dashboardId": "d1",
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
# display initiator must not contain exportType
|
|
205
|
+
{
|
|
206
|
+
"executionType": "REPORT",
|
|
207
|
+
"organizationId": "org1",
|
|
208
|
+
"workspaceId": "ws1",
|
|
209
|
+
"userId": "user1",
|
|
210
|
+
"attributes": [],
|
|
211
|
+
"filters": [],
|
|
212
|
+
"reportExecutionRequest": {},
|
|
213
|
+
"executionInitiator": {
|
|
214
|
+
"type": "display",
|
|
215
|
+
"dashboardId": "d1",
|
|
216
|
+
"exportType": "CSV",
|
|
217
|
+
},
|
|
218
|
+
},
|
|
113
219
|
],
|
|
114
220
|
)
|
|
115
221
|
def test_invalid_execution_context_schema(value, get_validator):
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/funs/fun1.py
RENAMED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# (C) 2024 GoodData Corporation
|
|
2
|
-
from typing import Optional
|
|
3
2
|
|
|
4
3
|
import pyarrow
|
|
5
4
|
from gooddata_flexconnect.function.function import FlexConnectFunction
|
|
@@ -19,7 +18,7 @@ class _SimpleFun1(FlexConnectFunction):
|
|
|
19
18
|
def call(
|
|
20
19
|
self,
|
|
21
20
|
parameters: dict,
|
|
22
|
-
columns:
|
|
21
|
+
columns: tuple[str, ...] | None,
|
|
23
22
|
headers: dict[str, list[str]],
|
|
24
23
|
) -> ArrowData:
|
|
25
24
|
return pyarrow.table(
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/funs/fun2.py
RENAMED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
# (C) 2024 GoodData Corporation
|
|
2
|
-
from typing import Optional
|
|
3
2
|
|
|
4
3
|
import pyarrow
|
|
5
4
|
from gooddata_flexconnect.function.function import FlexConnectFunction
|
|
6
5
|
from gooddata_flight_server import ArrowData, ServerContext
|
|
7
6
|
|
|
8
|
-
_DATA:
|
|
7
|
+
_DATA: pyarrow.Table | None = None
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
class _SimpleFun2(FlexConnectFunction):
|
|
@@ -21,7 +20,7 @@ class _SimpleFun2(FlexConnectFunction):
|
|
|
21
20
|
def call(
|
|
22
21
|
self,
|
|
23
22
|
parameters: dict,
|
|
24
|
-
columns:
|
|
23
|
+
columns: tuple[str, ...] | None,
|
|
25
24
|
headers: dict[str, list[str]],
|
|
26
25
|
) -> ArrowData:
|
|
27
26
|
assert _DATA is not None
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/funs/fun3.py
RENAMED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# (C) 2024 GoodData Corporation
|
|
2
2
|
import time
|
|
3
|
-
from typing import Optional
|
|
4
3
|
|
|
5
4
|
import pyarrow
|
|
6
5
|
from gooddata_flexconnect.function.function import FlexConnectFunction
|
|
7
6
|
from gooddata_flight_server import ArrowData
|
|
8
7
|
|
|
9
|
-
_DATA:
|
|
8
|
+
_DATA: pyarrow.Table | None = None
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
class _LongRunningFun(FlexConnectFunction):
|
|
@@ -22,7 +21,7 @@ class _LongRunningFun(FlexConnectFunction):
|
|
|
22
21
|
def call(
|
|
23
22
|
self,
|
|
24
23
|
parameters: dict,
|
|
25
|
-
columns:
|
|
24
|
+
columns: tuple[str, ...] | None,
|
|
26
25
|
headers: dict[str, list[str]],
|
|
27
26
|
) -> ArrowData:
|
|
28
27
|
# sleep is intentionally setup to be longer than the deadline for
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/funs/fun4.py
RENAMED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# (C) 2024 GoodData Corporation
|
|
2
2
|
import time
|
|
3
|
-
from typing import Optional
|
|
4
3
|
|
|
5
4
|
import pyarrow
|
|
6
5
|
from gooddata_flexconnect.function.function import FlexConnectFunction
|
|
7
6
|
from gooddata_flight_server import ArrowData
|
|
8
7
|
|
|
9
|
-
_DATA:
|
|
8
|
+
_DATA: pyarrow.Table | None = None
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
class _PollableFun(FlexConnectFunction):
|
|
@@ -22,7 +21,7 @@ class _PollableFun(FlexConnectFunction):
|
|
|
22
21
|
def call(
|
|
23
22
|
self,
|
|
24
23
|
parameters: dict,
|
|
25
|
-
columns:
|
|
24
|
+
columns: tuple[str, ...] | None,
|
|
26
25
|
headers: dict[str, list[str]],
|
|
27
26
|
) -> ArrowData:
|
|
28
27
|
# sleep is intentionally setup to be longer than one polling interval
|
|
@@ -11,7 +11,7 @@ dependency_groups =
|
|
|
11
11
|
setenv =
|
|
12
12
|
COVERAGE_CORE=sysmon
|
|
13
13
|
commands =
|
|
14
|
-
pytest -v --cov
|
|
14
|
+
pytest -v --cov --cov-report=xml tests {posargs} --json-report --json-report-file=.json-report-{envname}.json
|
|
15
15
|
|
|
16
16
|
[testenv:docs]
|
|
17
17
|
basepython = python3.14
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/assert_error_info.py
RENAMED
|
File without changes
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/function/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/json_schemas/__init__.py
RENAMED
|
File without changes
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/json_schemas/conftest.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/__init__.py
RENAMED
|
File without changes
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/conftest.py
RENAMED
|
File without changes
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/funs/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{gooddata_flexconnect-1.60.1.dev1 → gooddata_flexconnect-1.60.1.dev2}/tests/server/tls/ca-cert.pem
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|