feldera 0.134.0__tar.gz → 0.136.0__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.
Potentially problematic release.
This version of feldera might be problematic. Click here for more details.
- {feldera-0.134.0 → feldera-0.136.0}/PKG-INFO +1 -1
- {feldera-0.134.0 → feldera-0.136.0}/feldera/_callback_runner.py +10 -9
- {feldera-0.134.0 → feldera-0.136.0}/feldera/_helpers.py +2 -2
- {feldera-0.134.0 → feldera-0.136.0}/feldera/pipeline.py +10 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/rest/_httprequests.py +1 -1
- {feldera-0.134.0 → feldera-0.136.0}/feldera/rest/config.py +19 -5
- {feldera-0.134.0 → feldera-0.136.0}/feldera/rest/feldera_client.py +14 -7
- {feldera-0.134.0 → feldera-0.136.0}/feldera/testutils.py +7 -1
- {feldera-0.134.0 → feldera-0.136.0}/feldera.egg-info/PKG-INFO +1 -1
- {feldera-0.134.0 → feldera-0.136.0}/pyproject.toml +4 -1
- {feldera-0.134.0 → feldera-0.136.0}/README.md +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/__init__.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/enums.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/output_handler.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/pipeline_builder.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/rest/__init__.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/rest/_helpers.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/rest/errors.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/rest/feldera_config.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/rest/pipeline.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/rest/sql_table.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/rest/sql_view.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/runtime_config.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/stats.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera/tests/test_datafusionize.py +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera.egg-info/SOURCES.txt +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera.egg-info/dependency_links.txt +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera.egg-info/requires.txt +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/feldera.egg-info/top_level.txt +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/setup.cfg +0 -0
- {feldera-0.134.0 → feldera-0.136.0}/tests/test_uda.py +0 -0
|
@@ -39,14 +39,12 @@ class CallbackRunner(Thread):
|
|
|
39
39
|
"""
|
|
40
40
|
|
|
41
41
|
pipeline = self.client.get_pipeline(self.pipeline_name)
|
|
42
|
-
schema = pipeline.program_info["schema"]
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
break
|
|
43
|
+
schemas = pipeline.tables + pipeline.views
|
|
44
|
+
for schema in schemas:
|
|
45
|
+
if schema.name == self.view_name:
|
|
46
|
+
self.schema = schema
|
|
47
|
+
break
|
|
50
48
|
|
|
51
49
|
if self.schema is None:
|
|
52
50
|
raise ValueError(
|
|
@@ -66,7 +64,10 @@ class CallbackRunner(Thread):
|
|
|
66
64
|
case _CallbackRunnerInstruction.PipelineStarted:
|
|
67
65
|
# listen to the pipeline
|
|
68
66
|
gen_obj = self.client.listen_to_pipeline(
|
|
69
|
-
self.pipeline_name,
|
|
67
|
+
self.pipeline_name,
|
|
68
|
+
self.view_name,
|
|
69
|
+
format="json",
|
|
70
|
+
case_sensitive=self.schema.case_sensitive,
|
|
70
71
|
)
|
|
71
72
|
|
|
72
73
|
# if there is a queue set up, inform the main thread that the listener has been started, and it can
|
|
@@ -83,7 +84,7 @@ class CallbackRunner(Thread):
|
|
|
83
84
|
seq_no: Optional[int] = chunk.get("sequence_number")
|
|
84
85
|
if data is not None and seq_no is not None:
|
|
85
86
|
self.callback(
|
|
86
|
-
dataframe_from_response([data], self.schema), seq_no
|
|
87
|
+
dataframe_from_response([data], self.schema.fields), seq_no
|
|
87
88
|
)
|
|
88
89
|
|
|
89
90
|
if self.queue:
|
|
@@ -60,7 +60,7 @@ def ensure_dataframe_has_columns(df: pd.DataFrame):
|
|
|
60
60
|
)
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
def dataframe_from_response(buffer: list[list[dict]],
|
|
63
|
+
def dataframe_from_response(buffer: list[list[dict]], fields: list[dict]):
|
|
64
64
|
"""
|
|
65
65
|
Converts the response from Feldera to a pandas DataFrame.
|
|
66
66
|
"""
|
|
@@ -70,7 +70,7 @@ def dataframe_from_response(buffer: list[list[dict]], schema: dict):
|
|
|
70
70
|
decimal_col = []
|
|
71
71
|
uuid_col = []
|
|
72
72
|
|
|
73
|
-
for column in
|
|
73
|
+
for column in fields:
|
|
74
74
|
column_name = column["name"]
|
|
75
75
|
if not column["case_sensitive"]:
|
|
76
76
|
column_name = column_name.lower()
|
|
@@ -685,6 +685,7 @@ pipeline '{self.name}' to make checkpoint '{seq}'"""
|
|
|
685
685
|
checkpoint to complete syncing.
|
|
686
686
|
|
|
687
687
|
:raises FelderaAPIError: If no checkpoints have been made.
|
|
688
|
+
:raises RuntimeError: If syncing the checkpoint fails.
|
|
688
689
|
"""
|
|
689
690
|
|
|
690
691
|
uuid = self.client.sync_checkpoint(self.name)
|
|
@@ -702,6 +703,11 @@ pipeline '{self.name}' to make checkpoint '{seq}'"""
|
|
|
702
703
|
pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
703
704
|
)
|
|
704
705
|
status = self.sync_checkpoint_status(uuid)
|
|
706
|
+
if status == CheckpointStatus.Failure:
|
|
707
|
+
raise RuntimeError(
|
|
708
|
+
f"failed to sync checkpoint '{uuid}': ", status.get_error()
|
|
709
|
+
)
|
|
710
|
+
|
|
705
711
|
if status in [CheckpointStatus.InProgress, CheckpointStatus.Unknown]:
|
|
706
712
|
time.sleep(0.1)
|
|
707
713
|
continue
|
|
@@ -716,6 +722,9 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
716
722
|
If the checkpoint is currently being synchronized, returns
|
|
717
723
|
`CheckpointStatus.Unknown`.
|
|
718
724
|
|
|
725
|
+
Failures are not raised as runtime errors and must be explicitly
|
|
726
|
+
checked.
|
|
727
|
+
|
|
719
728
|
:param uuid: The checkpoint uuid.
|
|
720
729
|
"""
|
|
721
730
|
|
|
@@ -731,6 +740,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
731
740
|
if uuid == fail.get("uuid"):
|
|
732
741
|
failure = CheckpointStatus.Failure
|
|
733
742
|
failure.error = fail.get("error", "")
|
|
743
|
+
logging.error(f"failed to sync checkpoint '{uuid}': {failure.error}")
|
|
734
744
|
return failure
|
|
735
745
|
|
|
736
746
|
if (success is None) or UUID(uuid) > UUID(success):
|
|
@@ -26,7 +26,7 @@ class HttpRequests:
|
|
|
26
26
|
self.headers = {"User-Agent": "feldera-python-sdk/v1"}
|
|
27
27
|
self.requests_verify = config.requests_verify
|
|
28
28
|
|
|
29
|
-
if not self.requests_verify:
|
|
29
|
+
if isinstance(self.requests_verify, bool) and not self.requests_verify:
|
|
30
30
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
31
31
|
|
|
32
32
|
if self.config.api_key:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
|
+
import os
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
class Config:
|
|
@@ -8,12 +9,12 @@ class Config:
|
|
|
8
9
|
|
|
9
10
|
def __init__(
|
|
10
11
|
self,
|
|
11
|
-
url: str,
|
|
12
|
+
url: Optional[str] = None,
|
|
12
13
|
api_key: Optional[str] = None,
|
|
13
14
|
version: Optional[str] = None,
|
|
14
15
|
timeout: Optional[float] = None,
|
|
15
16
|
connection_timeout: Optional[float] = None,
|
|
16
|
-
requests_verify: bool = True,
|
|
17
|
+
requests_verify: bool | str = True,
|
|
17
18
|
) -> None:
|
|
18
19
|
"""
|
|
19
20
|
:param url: The url to the Feldera API (ex: https://try.feldera.com)
|
|
@@ -25,9 +26,22 @@ class Config:
|
|
|
25
26
|
library. `True` by default.
|
|
26
27
|
"""
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
BASE_URL = (
|
|
30
|
+
url
|
|
31
|
+
or os.environ.get("FELDERA_HOST")
|
|
32
|
+
or os.environ.get("FELDERA_BASE_URL")
|
|
33
|
+
or "http://localhost:8080"
|
|
34
|
+
)
|
|
35
|
+
self.url: str = BASE_URL
|
|
36
|
+
self.api_key: Optional[str] = os.environ.get("FELDERA_API_KEY", api_key)
|
|
30
37
|
self.version: Optional[str] = version or "v0"
|
|
31
38
|
self.timeout: Optional[float] = timeout
|
|
32
39
|
self.connection_timeout: Optional[float] = connection_timeout
|
|
33
|
-
|
|
40
|
+
|
|
41
|
+
FELDERA_TLS_INSECURE = True if os.environ.get("FELDERA_TLS_INSECURE") else False
|
|
42
|
+
FELDERA_HTTPS_TLS_CERT = os.environ.get("FELDERA_HTTPS_TLS_CERT")
|
|
43
|
+
requests_verify = not FELDERA_TLS_INSECURE
|
|
44
|
+
if requests_verify and FELDERA_HTTPS_TLS_CERT is not None:
|
|
45
|
+
requests_verify = FELDERA_HTTPS_TLS_CERT
|
|
46
|
+
|
|
47
|
+
self.requests_verify: bool | str = requests_verify
|
|
@@ -43,21 +43,24 @@ class FelderaClient:
|
|
|
43
43
|
|
|
44
44
|
def __init__(
|
|
45
45
|
self,
|
|
46
|
-
url: str,
|
|
46
|
+
url: Optional[str] = None,
|
|
47
47
|
api_key: Optional[str] = None,
|
|
48
48
|
timeout: Optional[float] = None,
|
|
49
49
|
connection_timeout: Optional[float] = None,
|
|
50
|
-
requests_verify: bool = True,
|
|
50
|
+
requests_verify: bool | str = True,
|
|
51
51
|
) -> None:
|
|
52
52
|
"""
|
|
53
|
-
:param url: The url to Feldera API (ex: https://try.feldera.com)
|
|
53
|
+
:param url: The url to Feldera API (ex: https://try.feldera.com). If
|
|
54
|
+
not set, attempts to read from the environment variable
|
|
55
|
+
`FELDERA_HOST`. Default: `http://localhost:8080`
|
|
54
56
|
:param api_key: The optional API key for Feldera
|
|
55
57
|
:param timeout: (optional) The amount of time in seconds that the
|
|
56
58
|
client will wait for a response before timing out.
|
|
57
|
-
:param connection_timeout: (optional) The amount of time in seconds
|
|
58
|
-
the client will wait to establish connection before timing out
|
|
59
|
+
:param connection_timeout: (optional) The amount of time in seconds
|
|
60
|
+
that the client will wait to establish connection before timing out
|
|
59
61
|
:param requests_verify: The `verify` parameter passed to the requests
|
|
60
|
-
library. `True` by default.
|
|
62
|
+
library. `True` by default. To use a self signed certificate, set
|
|
63
|
+
it to the path to the certificate.
|
|
61
64
|
"""
|
|
62
65
|
|
|
63
66
|
self.config = Config(
|
|
@@ -830,6 +833,7 @@ Reason: The pipeline is in a STOPPED state due to the following error:
|
|
|
830
833
|
backpressure: bool = True,
|
|
831
834
|
array: bool = False,
|
|
832
835
|
timeout: Optional[float] = None,
|
|
836
|
+
case_sensitive: bool = False,
|
|
833
837
|
):
|
|
834
838
|
"""
|
|
835
839
|
Listen for updates to views for pipeline, yields the chunks of data
|
|
@@ -845,6 +849,7 @@ Reason: The pipeline is in a STOPPED state due to the following error:
|
|
|
845
849
|
"json" format, the default value is False
|
|
846
850
|
|
|
847
851
|
:param timeout: The amount of time in seconds to listen to the stream for
|
|
852
|
+
:param case_sensitive: True if the table name is case sensitive or a reserved keyword, False by default
|
|
848
853
|
"""
|
|
849
854
|
|
|
850
855
|
params = {
|
|
@@ -855,6 +860,8 @@ Reason: The pipeline is in a STOPPED state due to the following error:
|
|
|
855
860
|
if format == "json":
|
|
856
861
|
params["array"] = _prepare_boolean_input(array)
|
|
857
862
|
|
|
863
|
+
table_name = f'"{table_name}"' if case_sensitive else table_name
|
|
864
|
+
|
|
858
865
|
resp = self.http.post(
|
|
859
866
|
path=f"/pipelines/{pipeline_name}/egress/{table_name}",
|
|
860
867
|
params=params,
|
|
@@ -982,7 +989,7 @@ Reason: The pipeline is in a STOPPED state due to the following error:
|
|
|
982
989
|
stream=True,
|
|
983
990
|
)
|
|
984
991
|
|
|
985
|
-
for chunk in resp.iter_lines(chunk_size=
|
|
992
|
+
for chunk in resp.iter_lines(chunk_size=1024):
|
|
986
993
|
if chunk:
|
|
987
994
|
yield json.loads(chunk, parse_float=Decimal)
|
|
988
995
|
|
|
@@ -23,6 +23,12 @@ KAFKA_SERVER = os.environ.get("FELDERA_KAFKA_SERVER", "localhost:19092")
|
|
|
23
23
|
PIPELINE_TO_KAFKA_SERVER = os.environ.get(
|
|
24
24
|
"FELDERA_PIPELINE_TO_KAFKA_SERVER", "redpanda:9092"
|
|
25
25
|
)
|
|
26
|
+
FELDERA_TLS_INSECURE = True if os.environ.get("FELDERA_TLS_INSECURE") else False
|
|
27
|
+
FELDERA_HTTPS_TLS_CERT = os.environ.get("FELDERA_HTTPS_TLS_CERT")
|
|
28
|
+
if not FELDERA_TLS_INSECURE and FELDERA_HTTPS_TLS_CERT is not None:
|
|
29
|
+
FELDERA_REQUESTS_VERIFY = FELDERA_HTTPS_TLS_CERT
|
|
30
|
+
else:
|
|
31
|
+
FELDERA_REQUESTS_VERIFY = not FELDERA_TLS_INSECURE
|
|
26
32
|
|
|
27
33
|
|
|
28
34
|
class _LazyClient:
|
|
@@ -36,7 +42,7 @@ class _LazyClient:
|
|
|
36
42
|
def _ensure(self):
|
|
37
43
|
if self._client is None:
|
|
38
44
|
self._client = FelderaClient(
|
|
39
|
-
|
|
45
|
+
connection_timeout=10,
|
|
40
46
|
)
|
|
41
47
|
return self._client
|
|
42
48
|
|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
name = "feldera"
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
description = "The feldera python client"
|
|
9
|
-
version = "0.
|
|
9
|
+
version = "0.136.0"
|
|
10
10
|
license = { text = "MIT" }
|
|
11
11
|
requires-python = ">=3.10"
|
|
12
12
|
authors = [
|
|
@@ -45,3 +45,6 @@ dev-dependencies = [
|
|
|
45
45
|
"sphinx==7.3.7",
|
|
46
46
|
"simplejson==3.20.1"
|
|
47
47
|
]
|
|
48
|
+
|
|
49
|
+
[tool.pytest.ini_options]
|
|
50
|
+
pythonpath = "feldera"
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|