feldera 0.117.0__py3-none-any.whl → 0.119.0__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.

Potentially problematic release.


This version of feldera might be problematic. Click here for more details.

feldera/pipeline.py CHANGED
@@ -142,6 +142,7 @@ class Pipeline:
142
142
  data: Dict | list,
143
143
  update_format: str = "raw",
144
144
  force: bool = False,
145
+ wait: bool = True,
145
146
  ):
146
147
  """
147
148
  Push this JSON data to the specified table of the pipeline.
@@ -155,6 +156,7 @@ class Pipeline:
155
156
  :param update_format: The update format of the JSON data to be pushed to the pipeline. Must be one of:
156
157
  "raw", "insert_delete". https://docs.feldera.com/formats/json#the-insertdelete-format
157
158
  :param force: `True` to push data even if the pipeline is paused. `False` by default.
159
+ :param wait: If True, blocks until this input has been processed by the pipeline
158
160
 
159
161
  :raises ValueError: If the update format is invalid.
160
162
  :raises FelderaAPIError: If the pipeline is not in a valid state to push data.
@@ -177,6 +179,7 @@ class Pipeline:
177
179
  update_format=update_format,
178
180
  array=array,
179
181
  force=force,
182
+ wait=wait,
180
183
  )
181
184
 
182
185
  def pause_connector(self, table_name: str, connector_name: str):
@@ -372,7 +375,7 @@ method or use `Pipeline.resume()` to resume a paused pipeline."""
372
375
  return
373
376
 
374
377
  self.client.pause_pipeline(
375
- self.name, "Unable to START the pipeline.\n", timeout_s
378
+ self.name, "Unable to START the pipeline.\n", wait=wait, timeout_s=timeout_s
376
379
  )
377
380
  self.__setup_output_listeners()
378
381
  self.resume(timeout_s=timeout_s)
@@ -506,9 +509,11 @@ metrics"""
506
509
  queue.put(_CallbackRunnerInstruction.RanToCompletion)
507
510
 
508
511
  if len(self.views_tx) > 0:
509
- for view_name, queue in self.views_tx.pop().items():
510
- # block until the callback runner has been stopped
511
- queue.join()
512
+ while self.views_tx:
513
+ view = self.views_tx.pop()
514
+ for view_name, queue in view.items():
515
+ # block until the callback runner has been stopped
516
+ queue.join()
512
517
 
513
518
  time.sleep(3)
514
519
  self.client.stop_pipeline(
@@ -45,8 +45,8 @@ class PipelineBuilder:
45
45
  self.udf_toml: str = udf_toml
46
46
  self.compilation_profile: CompilationProfile = compilation_profile
47
47
  self.runtime_config: RuntimeConfig = runtime_config
48
- self.runtime_version: Optional[str] = runtime_version or os.environ.get(
49
- "FELDERA_RUNTIME_VERSION"
48
+ self.runtime_version: Optional[str] = os.environ.get(
49
+ "FELDERA_RUNTIME_VERSION", runtime_version
50
50
  )
51
51
 
52
52
  def create(self) -> Pipeline:
@@ -113,6 +113,7 @@ class PipelineBuilder:
113
113
  udf_toml=self.udf_toml,
114
114
  program_config={
115
115
  "profile": self.compilation_profile.value,
116
+ "runtime_version": self.runtime_version,
116
117
  },
117
118
  runtime_config=self.runtime_config.to_dict(),
118
119
  )
@@ -8,7 +8,7 @@ from typing import Generator, Mapping
8
8
 
9
9
  from feldera.rest.config import Config
10
10
  from feldera.rest.feldera_config import FelderaConfig
11
- from feldera.rest.errors import FelderaTimeoutError
11
+ from feldera.rest.errors import FelderaTimeoutError, FelderaAPIError
12
12
  from feldera.rest.pipeline import Pipeline
13
13
  from feldera.rest._httprequests import HttpRequests
14
14
  from feldera.rest._helpers import client_version
@@ -67,7 +67,7 @@ class FelderaClient:
67
67
  config = self.get_config()
68
68
  version = client_version()
69
69
  if config.version != version:
70
- logging.warn(
70
+ logging.warning(
71
71
  f"Client is on version {version} while server is at "
72
72
  f"{config.version}. There could be incompatibilities."
73
73
  )
@@ -593,7 +593,9 @@ Reason: The pipeline is in a STOPPED state due to the following error:
593
593
  update_format: str = "raw",
594
594
  json_flavor: Optional[str] = None,
595
595
  serialize: bool = True,
596
- ):
596
+ wait: bool = True,
597
+ wait_timeout_s: Optional[float] = None,
598
+ ) -> str:
597
599
  """
598
600
  Insert data into a pipeline
599
601
 
@@ -610,6 +612,11 @@ Reason: The pipeline is in a STOPPED state due to the following error:
610
612
  "debezium_mysql", "snowflake", "kafka_connect_json_converter", "pandas"
611
613
  :param data: The data to insert
612
614
  :param serialize: If True, the data will be serialized to JSON. True by default
615
+ :param wait: If True, blocks until this input has been processed by the pipeline
616
+ :param wait_timeout_s: The timeout in seconds to wait for this set of
617
+ inputs to be processed by the pipeline. None by default
618
+
619
+ :returns: The completion token to this input.
613
620
  """
614
621
 
615
622
  if format not in ["json", "csv"]:
@@ -671,7 +678,7 @@ Reason: The pipeline is in a STOPPED state due to the following error:
671
678
  content_type = "text/csv"
672
679
  data = bytes(str(data), "utf-8")
673
680
 
674
- self.http.post(
681
+ resp = self.http.post(
675
682
  path=f"/pipelines/{pipeline_name}/ingress/{table_name}",
676
683
  params=params,
677
684
  content_type=content_type,
@@ -679,6 +686,74 @@ Reason: The pipeline is in a STOPPED state due to the following error:
679
686
  serialize=serialize,
680
687
  )
681
688
 
689
+ token = resp.get("token")
690
+ if token is None:
691
+ raise FelderaAPIError("response did not contain a completion token", resp)
692
+
693
+ if not wait:
694
+ return token
695
+
696
+ self.wait_for_token(pipeline_name, token, timeout_s=wait_timeout_s)
697
+
698
+ return token
699
+
700
+ def wait_for_token(
701
+ self, pipeline_name: str, token: str, timeout_s: Optional[float] = 600
702
+ ):
703
+ """
704
+ Blocks until all records represented by this completion token have
705
+ been processed.
706
+
707
+ :param pipeline_name: The name of the pipeline
708
+ :param token: The token to check for completion
709
+ :param timeout_s: The amount of time in seconds to wait for the pipeline
710
+ to process these records. Default 600s
711
+ """
712
+
713
+ params = {
714
+ "token": token,
715
+ }
716
+
717
+ start = time.monotonic()
718
+ end = start + timeout_s if timeout_s else None
719
+ initial_backoff = 0.1
720
+ max_backoff = 5
721
+ exponent = 1.2
722
+ retries = 0
723
+
724
+ while True:
725
+ if end:
726
+ if time.monotonic() > end:
727
+ raise FelderaTimeoutError(
728
+ f"timeout error: pipeline '{pipeline_name}' did not"
729
+ f" process records represented by token {token} within"
730
+ f" {timeout_s}"
731
+ )
732
+
733
+ resp = self.http.get(
734
+ path=f"/pipelines/{pipeline_name}/completion_status", params=params
735
+ )
736
+
737
+ status: Optional[str] = resp.get("status")
738
+ if status is None:
739
+ raise FelderaAPIError(
740
+ f"got empty status when checking for completion status for token: {token}",
741
+ resp,
742
+ )
743
+
744
+ if status.lower() == "complete":
745
+ break
746
+
747
+ elapsed = time.monotonic() - start
748
+ logging.debug(
749
+ f"still waiting for inputs represented by {token} to be processed; elapsed: {elapsed}s"
750
+ )
751
+
752
+ retries += 1
753
+ backoff = min(max_backoff, initial_backoff * (exponent**retries))
754
+
755
+ time.sleep(backoff)
756
+
682
757
  def listen_to_pipeline(
683
758
  self,
684
759
  pipeline_name: str,
feldera/stats.py CHANGED
@@ -16,7 +16,7 @@ class PipelineStatistics:
16
16
 
17
17
  self.global_metrics: GlobalPipelineMetrics = GlobalPipelineMetrics()
18
18
  self.suspend_error: Optional[Any] = None
19
- self.inputs: Mapping[List[InputEndpointStatus()]] = {}
19
+ self.inputs: Mapping[List[InputEndpointStatus]] = {}
20
20
  self.outputs: Mapping[List[OutputEndpointStatus]] = {}
21
21
 
22
22
  @classmethod
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: feldera
3
- Version: 0.117.0
3
+ Version: 0.119.0
4
4
  Summary: The feldera python client
5
5
  Author-email: Feldera Team <dev@feldera.com>
6
6
  License: MIT
@@ -84,7 +84,7 @@ cd python && python3 -m pytest tests/
84
84
  - This will detect and run all test files that match the pattern `test_*.py` or
85
85
  `*_test.py`.
86
86
  - By default, the tests expect a running Feldera instance at `http://localhost:8080`.
87
- To override the default endpoint, set the `FELDERA_BASE_URL` environment variable.
87
+ To override the default endpoint, set the `FELDERA_HOST` environment variable.
88
88
 
89
89
  To run tests from a specific file:
90
90
 
@@ -3,21 +3,21 @@ feldera/_callback_runner.py,sha256=-2hYG70cEkvz4BiOfUTARaH-2Rlv0Qcz-ilvodgyK10,4
3
3
  feldera/_helpers.py,sha256=rN0WuGSCCQlXWFMimZUQrgs-LJAfUo074d79sLElncQ,3023
4
4
  feldera/enums.py,sha256=MTHBojVANsdRnjbrzCyIOniDIUaH8nTYRfxB7QvajEE,9570
5
5
  feldera/output_handler.py,sha256=64J3ljhOaKIhxdjOKYi-BUz_HnMwROfmN8eE-btYygU,1930
6
- feldera/pipeline.py,sha256=85goeiKa4sX-Os9edYv2S_vBsqVEfZ7qMAOU1qrWKPg,37580
7
- feldera/pipeline_builder.py,sha256=25tncJd-qiuHWZOezU34oGfDJqFAdjBEMd9QipNfswc,4195
6
+ feldera/pipeline.py,sha256=ZkmIU0nxpXplCl7iLh6XtdiCZtkR5GGKW33J4gdt1ig,37821
7
+ feldera/pipeline_builder.py,sha256=a750hp5SgTmlyrobTHFh1fTaK9Ed4A5qnXaYRctRM-8,4250
8
8
  feldera/runtime_config.py,sha256=MuYJPd5G_hnu_eDz4ge4BfYvSBSOvOEtv4NYh5sEwqU,4452
9
- feldera/stats.py,sha256=XBhkRsV7FXErwWuPP0i3q9W77mzkMo-oThPVEZy5y3U,5028
9
+ feldera/stats.py,sha256=eZxq51bUV3mlo6BW43DUHwmG1wpLs04rVECxOGojqxU,5026
10
10
  feldera/rest/__init__.py,sha256=Eg-EKUU3RSTDcdxTR_7wNDnCly8VpXEzsZCQUmf-y2M,308
11
11
  feldera/rest/_helpers.py,sha256=q7jWInKp9IiIli8N5o31lDG3hNUbcsJqufZXYHG04ps,222
12
12
  feldera/rest/_httprequests.py,sha256=w8tD-_3spAf4vgalJQceIHQ7qw1uvxprDFM2oz3P5QU,7559
13
13
  feldera/rest/config.py,sha256=DYzZKngDEhouTEwqVFd-rDrBN9tWqsU07Jl_BTT4mXs,1008
14
14
  feldera/rest/errors.py,sha256=b4i2JjrbSmej7jdko_FL8UeXklLKenSipwMT80jowaM,1720
15
- feldera/rest/feldera_client.py,sha256=Kz4_JLblaJtxtXcbBhoTpjiq123HvRPioNyGB8Jiu2o,30218
15
+ feldera/rest/feldera_client.py,sha256=tU99wyMDNkyHerom1QKeg1WZmno7bLNrIzbU2f98-7U,32855
16
16
  feldera/rest/feldera_config.py,sha256=1pnGbLFMSLvp7Qh_OlPLALSKCSHIktNWKvx6gYU00U4,1374
17
17
  feldera/rest/pipeline.py,sha256=Rmbflbwjvd86iZ5aSJ5b_bTSs6vgvEKQFwMZDtm0nxE,2835
18
18
  feldera/rest/sql_table.py,sha256=qrw-YwMzx5T81zDefNO1KOx7EyypFz1vPwGBzSUB7kc,652
19
19
  feldera/rest/sql_view.py,sha256=hN12mPM0mvwLCIPYywpb12s9Hd2Ws31IlTMXPriMisw,644
20
- feldera-0.117.0.dist-info/METADATA,sha256=WIxaKR_8gNIXNle4oOJ6aUY4X7oYPzebL9Jixzm-o8I,4057
21
- feldera-0.117.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
22
- feldera-0.117.0.dist-info/top_level.txt,sha256=fB6yTqrQiO6RCbY1xP2T_mpPoTjDFtJvkJJodiee7d0,8
23
- feldera-0.117.0.dist-info/RECORD,,
20
+ feldera-0.119.0.dist-info/METADATA,sha256=a-EKosH2QXmtKRGM2XhxxM-Q8G8kYUWd5j8xIaOq-Wc,4053
21
+ feldera-0.119.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
22
+ feldera-0.119.0.dist-info/top_level.txt,sha256=fB6yTqrQiO6RCbY1xP2T_mpPoTjDFtJvkJJodiee7d0,8
23
+ feldera-0.119.0.dist-info/RECORD,,