feldera 0.100.0__tar.gz → 0.101.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.

Files changed (36) hide show
  1. {feldera-0.100.0 → feldera-0.101.0}/PKG-INFO +45 -16
  2. feldera-0.101.0/README.md +129 -0
  3. {feldera-0.100.0 → feldera-0.101.0}/feldera/_callback_runner.py +8 -7
  4. {feldera-0.100.0 → feldera-0.101.0}/feldera/pipeline.py +5 -2
  5. {feldera-0.100.0 → feldera-0.101.0}/feldera/pipeline_builder.py +2 -2
  6. {feldera-0.100.0 → feldera-0.101.0}/feldera/rest/feldera_client.py +2 -2
  7. {feldera-0.100.0 → feldera-0.101.0}/feldera/runtime_config.py +9 -0
  8. {feldera-0.100.0 → feldera-0.101.0}/feldera.egg-info/PKG-INFO +45 -16
  9. {feldera-0.100.0 → feldera-0.101.0}/feldera.egg-info/SOURCES.txt +3 -3
  10. {feldera-0.100.0 → feldera-0.101.0}/pyproject.toml +1 -1
  11. feldera-0.101.0/tests/test_pipeline_builder.py +53 -0
  12. feldera-0.101.0/tests/test_shared_pipeline0.py +593 -0
  13. feldera-0.101.0/tests/test_shared_pipeline1.py +72 -0
  14. {feldera-0.100.0 → feldera-0.101.0}/tests/test_udf.py +0 -1
  15. feldera-0.100.0/README.md +0 -100
  16. feldera-0.100.0/tests/test_pipeline.py +0 -263
  17. feldera-0.100.0/tests/test_pipeline_builder.py +0 -1199
  18. feldera-0.100.0/tests/test_variant.py +0 -102
  19. {feldera-0.100.0 → feldera-0.101.0}/feldera/__init__.py +0 -0
  20. {feldera-0.100.0 → feldera-0.101.0}/feldera/_helpers.py +0 -0
  21. {feldera-0.100.0 → feldera-0.101.0}/feldera/enums.py +0 -0
  22. {feldera-0.100.0 → feldera-0.101.0}/feldera/output_handler.py +0 -0
  23. {feldera-0.100.0 → feldera-0.101.0}/feldera/rest/__init__.py +0 -0
  24. {feldera-0.100.0 → feldera-0.101.0}/feldera/rest/_helpers.py +0 -0
  25. {feldera-0.100.0 → feldera-0.101.0}/feldera/rest/_httprequests.py +0 -0
  26. {feldera-0.100.0 → feldera-0.101.0}/feldera/rest/config.py +0 -0
  27. {feldera-0.100.0 → feldera-0.101.0}/feldera/rest/errors.py +0 -0
  28. {feldera-0.100.0 → feldera-0.101.0}/feldera/rest/feldera_config.py +0 -0
  29. {feldera-0.100.0 → feldera-0.101.0}/feldera/rest/pipeline.py +0 -0
  30. {feldera-0.100.0 → feldera-0.101.0}/feldera/rest/sql_table.py +0 -0
  31. {feldera-0.100.0 → feldera-0.101.0}/feldera/rest/sql_view.py +0 -0
  32. {feldera-0.100.0 → feldera-0.101.0}/feldera/stats.py +0 -0
  33. {feldera-0.100.0 → feldera-0.101.0}/feldera.egg-info/dependency_links.txt +0 -0
  34. {feldera-0.100.0 → feldera-0.101.0}/feldera.egg-info/requires.txt +0 -0
  35. {feldera-0.100.0 → feldera-0.101.0}/feldera.egg-info/top_level.txt +0 -0
  36. {feldera-0.100.0 → feldera-0.101.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: feldera
3
- Version: 0.100.0
3
+ Version: 0.101.0
4
4
  Summary: The feldera python client
5
5
  Author-email: Feldera Team <dev@feldera.com>
6
6
  License: MIT
@@ -54,10 +54,11 @@ If you have cloned the Feldera repo, you can install the python SDK as follows:
54
54
  pip install python/
55
55
  ```
56
56
 
57
- Checkout the docs [here](./feldera/__init__.py) for an example on how to use the SDK.
58
-
59
57
  ## Documentation
60
58
 
59
+ The Python SDK documentation is available at
60
+ [Feldera Python SDK Docs](https://docs.feldera.com/python).
61
+
61
62
  To build the html documentation run:
62
63
 
63
64
  Ensure that you have sphinx installed. If not, install it using `pip install sphinx`.
@@ -77,27 +78,23 @@ To clean the build, run `make clean`.
77
78
  To run unit tests:
78
79
 
79
80
  ```bash
80
- (cd python && python3 -m unittest)
81
+ cd python && python3 -m pytest tests/
81
82
  ```
82
83
 
83
- > ⚠️ Running the unit tests will **delete all existing pipelines**.
84
-
85
- The following command runs end-to-end tests. You'll need a pipeline
86
- manager running at `http://localhost:8080`. For the pipeline builder
87
- tests, you'll also need a broker available at `localhost:9092` and
88
- (from the pipelines) `redpanda:19092`. (To change those locations,
89
- set the environment variables listed in `python/tests/__init__.py`.)
90
-
91
- ```bash
92
- (cd python && python3 -m pytest tests)
93
- ```
84
+ - This will detect and run all test files that match the pattern `test_*.py` or
85
+ `*_test.py`.
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.
94
88
 
95
89
  To run tests from a specific file:
96
90
 
97
91
  ```bash
98
- (cd python && python3 -m unittest ./tests/path-to-file.py)
92
+ (cd python && python3 -m pytest ./tests/path-to-file.py)
99
93
  ```
100
94
 
95
+ #### Running Aggregate Tests
96
+
97
+ The aggregate tests validate end-to-end correctness of SQL functionality.
101
98
  To run the aggregate tests use:
102
99
 
103
100
  ```bash
@@ -105,6 +102,38 @@ cd python
105
102
  PYTHONPATH=`pwd` python3 ./tests/aggregate_tests/main.py
106
103
  ```
107
104
 
105
+ ### Reducing Compilation Cycles
106
+
107
+ To reduce redundant compilation cycles during testing:
108
+
109
+ * **Inherit from `SharedTestPipeline`** instead of `unittest.TestCase`.
110
+ * **Define DDLs** (e.g., `CREATE TABLE`, `CREATE VIEW`) in the **docstring** of each test method.
111
+ * All DDLs from all test functions in the class are combined and compiled into a single pipeline.
112
+ * If a table or view is already defined in one test, it can be used directly in others without redefinition.
113
+ * Ensure that all table and view names are unique within the class.
114
+ * Use `@enterprise_only` on tests that require Enterprise features. Their DDLs will be skipped on OSS builds.
115
+ * Use `self.set_runtime_config(...)` to override the default pipeline config.
116
+ * Reset it at the end using `self.reset_runtime_config()`.
117
+ * Access the shared pipeline via `self.pipeline`.
118
+
119
+ #### Example
120
+
121
+ ```python
122
+ from tests.shared_test_pipeline import SharedTestPipeline
123
+
124
+ class TestAverage(SharedTestPipeline):
125
+ def test_average(self):
126
+ """
127
+ CREATE TABLE students(id INT, name STRING);
128
+ CREATE MATERIALIZED VIEW v AS SELECT * FROM students;
129
+ """
130
+ ...
131
+ self.pipeline.start()
132
+ self.pipeline.input_pandas("students", df)
133
+ self.pipeline.wait_for_completion(True)
134
+ ...
135
+ ```
136
+
108
137
  ## Linting and formatting
109
138
 
110
139
  Use [Ruff] to run the lint checks that will be executed by the
@@ -0,0 +1,129 @@
1
+ # Feldera Python SDK
2
+
3
+ Feldera Python is the Feldera SDK for Python developers.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install feldera
9
+ ```
10
+
11
+ ### Installing from Github
12
+
13
+ ```bash
14
+ pip install git+https://github.com/feldera/feldera#subdirectory=python
15
+ ```
16
+
17
+ Similarly, to install from a specific branch:
18
+
19
+ ```bash
20
+ $ pip install git+https://github.com/feldera/feldera@{BRANCH_NAME}#subdirectory=python
21
+ ```
22
+
23
+ Replace `{BRANCH_NAME}` with the name of the branch you want to install from.
24
+
25
+ ### Installing from Local Directory
26
+
27
+ If you have cloned the Feldera repo, you can install the python SDK as follows:
28
+
29
+ ```bash
30
+ # the Feldera Python SDK is present inside the python/ directory
31
+ pip install python/
32
+ ```
33
+
34
+ ## Documentation
35
+
36
+ The Python SDK documentation is available at
37
+ [Feldera Python SDK Docs](https://docs.feldera.com/python).
38
+
39
+ To build the html documentation run:
40
+
41
+ Ensure that you have sphinx installed. If not, install it using `pip install sphinx`.
42
+
43
+ Then run the following commands:
44
+
45
+ ```bash
46
+ cd docs
47
+ sphinx-apidoc -o . ../feldera
48
+ make html
49
+ ```
50
+
51
+ To clean the build, run `make clean`.
52
+
53
+ ## Testing
54
+
55
+ To run unit tests:
56
+
57
+ ```bash
58
+ cd python && python3 -m pytest tests/
59
+ ```
60
+
61
+ - This will detect and run all test files that match the pattern `test_*.py` or
62
+ `*_test.py`.
63
+ - By default, the tests expect a running Feldera instance at `http://localhost:8080`.
64
+ To override the default endpoint, set the `FELDERA_BASE_URL` environment variable.
65
+
66
+ To run tests from a specific file:
67
+
68
+ ```bash
69
+ (cd python && python3 -m pytest ./tests/path-to-file.py)
70
+ ```
71
+
72
+ #### Running Aggregate Tests
73
+
74
+ The aggregate tests validate end-to-end correctness of SQL functionality.
75
+ To run the aggregate tests use:
76
+
77
+ ```bash
78
+ cd python
79
+ PYTHONPATH=`pwd` python3 ./tests/aggregate_tests/main.py
80
+ ```
81
+
82
+ ### Reducing Compilation Cycles
83
+
84
+ To reduce redundant compilation cycles during testing:
85
+
86
+ * **Inherit from `SharedTestPipeline`** instead of `unittest.TestCase`.
87
+ * **Define DDLs** (e.g., `CREATE TABLE`, `CREATE VIEW`) in the **docstring** of each test method.
88
+ * All DDLs from all test functions in the class are combined and compiled into a single pipeline.
89
+ * If a table or view is already defined in one test, it can be used directly in others without redefinition.
90
+ * Ensure that all table and view names are unique within the class.
91
+ * Use `@enterprise_only` on tests that require Enterprise features. Their DDLs will be skipped on OSS builds.
92
+ * Use `self.set_runtime_config(...)` to override the default pipeline config.
93
+ * Reset it at the end using `self.reset_runtime_config()`.
94
+ * Access the shared pipeline via `self.pipeline`.
95
+
96
+ #### Example
97
+
98
+ ```python
99
+ from tests.shared_test_pipeline import SharedTestPipeline
100
+
101
+ class TestAverage(SharedTestPipeline):
102
+ def test_average(self):
103
+ """
104
+ CREATE TABLE students(id INT, name STRING);
105
+ CREATE MATERIALIZED VIEW v AS SELECT * FROM students;
106
+ """
107
+ ...
108
+ self.pipeline.start()
109
+ self.pipeline.input_pandas("students", df)
110
+ self.pipeline.wait_for_completion(True)
111
+ ...
112
+ ```
113
+
114
+ ## Linting and formatting
115
+
116
+ Use [Ruff] to run the lint checks that will be executed by the
117
+ precommit hook when a PR is submitted:
118
+
119
+ ```bash
120
+ ruff check python/
121
+ ```
122
+
123
+ To reformat the code in the same way as the precommit hook:
124
+
125
+ ```bash
126
+ ruff format
127
+ ```
128
+
129
+ [Ruff]: https://github.com/astral-sh/ruff
@@ -54,12 +54,12 @@ class CallbackRunner(Thread):
54
54
  )
55
55
 
56
56
  # by default, we assume that the pipeline has been started
57
- ack: _CallbackRunnerInstruction = _CallbackRunnerInstruction.PipelineStarted
57
+ ack = _CallbackRunnerInstruction.PipelineStarted
58
58
 
59
59
  # if there is Queue, we wait for the instruction to start the pipeline
60
60
  # this means that we are listening to the pipeline before running it, therefore, all data should be received
61
61
  if self.queue:
62
- ack: _CallbackRunnerInstruction = self.queue.get()
62
+ ack = self.queue.get()
63
63
 
64
64
  match ack:
65
65
  # if the pipeline has actually been started, we start a listener
@@ -77,11 +77,12 @@ class CallbackRunner(Thread):
77
77
 
78
78
  for chunk in gen_obj:
79
79
  chunk: dict = chunk
80
- data: list[dict] = chunk.get("json_data")
81
- seq_no: int = chunk.get("sequence_number")
82
-
83
- if data is not None:
84
- self.callback(dataframe_from_response([data], schema), seq_no)
80
+ data: Optional[list[dict]] = chunk.get("json_data")
81
+ seq_no: Optional[int] = chunk.get("sequence_number")
82
+ if data is not None and seq_no is not None:
83
+ self.callback(
84
+ dataframe_from_response([data], self.schema), seq_no
85
+ )
85
86
 
86
87
  if self.queue:
87
88
  try:
@@ -473,10 +473,13 @@ metrics"""
473
473
  pipeline to stop.
474
474
  """
475
475
 
476
- if len(self.views_tx) > 0:
477
- for _, queue in self.views_tx.pop().items():
476
+ for view_queue in self.views_tx:
477
+ for _, queue in view_queue.items():
478
478
  # sends a message to the callback runner to stop listening
479
479
  queue.put(_CallbackRunnerInstruction.RanToCompletion)
480
+
481
+ if len(self.views_tx) > 0:
482
+ for view_name, queue in self.views_tx.pop().items():
480
483
  # block until the callback runner has been stopped
481
484
  queue.join()
482
485
 
@@ -2,7 +2,7 @@ from feldera.rest.feldera_client import FelderaClient
2
2
  from feldera.rest.pipeline import Pipeline as InnerPipeline
3
3
  from feldera.pipeline import Pipeline
4
4
  from feldera.enums import CompilationProfile
5
- from feldera.runtime_config import RuntimeConfig, Resources
5
+ from feldera.runtime_config import RuntimeConfig
6
6
  from feldera.rest.errors import FelderaAPIError
7
7
 
8
8
 
@@ -29,7 +29,7 @@ class PipelineBuilder:
29
29
  udf_toml: str = "",
30
30
  description: str = "",
31
31
  compilation_profile: CompilationProfile = CompilationProfile.OPTIMIZED,
32
- runtime_config: RuntimeConfig = RuntimeConfig(resources=Resources()),
32
+ runtime_config: RuntimeConfig = RuntimeConfig.default(),
33
33
  ):
34
34
  self.client: FelderaClient = client
35
35
  self.name: str | None = name
@@ -454,11 +454,11 @@ Reason: The pipeline is in a STOPPED state due to the following error:
454
454
  pipeline_name: str,
455
455
  table_name: str,
456
456
  format: str,
457
- data: list[list | str | dict] | dict,
457
+ data: list[list | str | dict] | dict | str,
458
458
  array: bool = False,
459
459
  force: bool = False,
460
460
  update_format: str = "raw",
461
- json_flavor: str = None,
461
+ json_flavor: Optional[str] = None,
462
462
  serialize: bool = True,
463
463
  ):
464
464
  """
@@ -1,3 +1,4 @@
1
+ import os
1
2
  from typing import Optional, Any, Mapping
2
3
 
3
4
 
@@ -72,6 +73,7 @@ class RuntimeConfig:
72
73
  clock_resolution_usecs: Optional[int] = None,
73
74
  provisioning_timeout_secs: Optional[int] = None,
74
75
  resources: Optional[Resources] = None,
76
+ runtime_version: Optional[str] = None,
75
77
  ):
76
78
  self.workers = workers
77
79
  self.tracing = tracing
@@ -81,6 +83,9 @@ class RuntimeConfig:
81
83
  self.min_batch_size_records = min_batch_size_records
82
84
  self.clock_resolution_usecs = clock_resolution_usecs
83
85
  self.provisioning_timeout_secs = provisioning_timeout_secs
86
+ self.runtime_version = runtime_version or os.environ.get(
87
+ "FELDERA_RUNTIME_VERSION"
88
+ )
84
89
  if resources is not None:
85
90
  self.resources = resources.__dict__
86
91
  if isinstance(storage, bool):
@@ -88,6 +93,10 @@ class RuntimeConfig:
88
93
  if isinstance(storage, Storage):
89
94
  self.storage = storage.__dict__
90
95
 
96
+ @staticmethod
97
+ def default() -> "RuntimeConfig":
98
+ return RuntimeConfig(resources=Resources())
99
+
91
100
  @classmethod
92
101
  def from_dict(cls, d: Mapping[str, Any]):
93
102
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: feldera
3
- Version: 0.100.0
3
+ Version: 0.101.0
4
4
  Summary: The feldera python client
5
5
  Author-email: Feldera Team <dev@feldera.com>
6
6
  License: MIT
@@ -54,10 +54,11 @@ If you have cloned the Feldera repo, you can install the python SDK as follows:
54
54
  pip install python/
55
55
  ```
56
56
 
57
- Checkout the docs [here](./feldera/__init__.py) for an example on how to use the SDK.
58
-
59
57
  ## Documentation
60
58
 
59
+ The Python SDK documentation is available at
60
+ [Feldera Python SDK Docs](https://docs.feldera.com/python).
61
+
61
62
  To build the html documentation run:
62
63
 
63
64
  Ensure that you have sphinx installed. If not, install it using `pip install sphinx`.
@@ -77,27 +78,23 @@ To clean the build, run `make clean`.
77
78
  To run unit tests:
78
79
 
79
80
  ```bash
80
- (cd python && python3 -m unittest)
81
+ cd python && python3 -m pytest tests/
81
82
  ```
82
83
 
83
- > ⚠️ Running the unit tests will **delete all existing pipelines**.
84
-
85
- The following command runs end-to-end tests. You'll need a pipeline
86
- manager running at `http://localhost:8080`. For the pipeline builder
87
- tests, you'll also need a broker available at `localhost:9092` and
88
- (from the pipelines) `redpanda:19092`. (To change those locations,
89
- set the environment variables listed in `python/tests/__init__.py`.)
90
-
91
- ```bash
92
- (cd python && python3 -m pytest tests)
93
- ```
84
+ - This will detect and run all test files that match the pattern `test_*.py` or
85
+ `*_test.py`.
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.
94
88
 
95
89
  To run tests from a specific file:
96
90
 
97
91
  ```bash
98
- (cd python && python3 -m unittest ./tests/path-to-file.py)
92
+ (cd python && python3 -m pytest ./tests/path-to-file.py)
99
93
  ```
100
94
 
95
+ #### Running Aggregate Tests
96
+
97
+ The aggregate tests validate end-to-end correctness of SQL functionality.
101
98
  To run the aggregate tests use:
102
99
 
103
100
  ```bash
@@ -105,6 +102,38 @@ cd python
105
102
  PYTHONPATH=`pwd` python3 ./tests/aggregate_tests/main.py
106
103
  ```
107
104
 
105
+ ### Reducing Compilation Cycles
106
+
107
+ To reduce redundant compilation cycles during testing:
108
+
109
+ * **Inherit from `SharedTestPipeline`** instead of `unittest.TestCase`.
110
+ * **Define DDLs** (e.g., `CREATE TABLE`, `CREATE VIEW`) in the **docstring** of each test method.
111
+ * All DDLs from all test functions in the class are combined and compiled into a single pipeline.
112
+ * If a table or view is already defined in one test, it can be used directly in others without redefinition.
113
+ * Ensure that all table and view names are unique within the class.
114
+ * Use `@enterprise_only` on tests that require Enterprise features. Their DDLs will be skipped on OSS builds.
115
+ * Use `self.set_runtime_config(...)` to override the default pipeline config.
116
+ * Reset it at the end using `self.reset_runtime_config()`.
117
+ * Access the shared pipeline via `self.pipeline`.
118
+
119
+ #### Example
120
+
121
+ ```python
122
+ from tests.shared_test_pipeline import SharedTestPipeline
123
+
124
+ class TestAverage(SharedTestPipeline):
125
+ def test_average(self):
126
+ """
127
+ CREATE TABLE students(id INT, name STRING);
128
+ CREATE MATERIALIZED VIEW v AS SELECT * FROM students;
129
+ """
130
+ ...
131
+ self.pipeline.start()
132
+ self.pipeline.input_pandas("students", df)
133
+ self.pipeline.wait_for_completion(True)
134
+ ...
135
+ ```
136
+
108
137
  ## Linting and formatting
109
138
 
110
139
  Use [Ruff] to run the lint checks that will be executed by the
@@ -24,7 +24,7 @@ feldera/rest/feldera_config.py
24
24
  feldera/rest/pipeline.py
25
25
  feldera/rest/sql_table.py
26
26
  feldera/rest/sql_view.py
27
- tests/test_pipeline.py
28
27
  tests/test_pipeline_builder.py
29
- tests/test_udf.py
30
- tests/test_variant.py
28
+ tests/test_shared_pipeline0.py
29
+ tests/test_shared_pipeline1.py
30
+ tests/test_udf.py
@@ -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.100.0"
9
+ version = "0.101.0"
10
10
  license = { text = "MIT" }
11
11
  requires-python = ">=3.10"
12
12
  authors = [
@@ -0,0 +1,53 @@
1
+ import unittest
2
+ from tests import TEST_CLIENT
3
+ from feldera import PipelineBuilder
4
+
5
+
6
+ class TestPipelineBuilder(unittest.TestCase):
7
+ def test_connector_orchestration(self):
8
+ sql = """
9
+ CREATE TABLE numbers (
10
+ num INT
11
+ ) WITH (
12
+ 'connectors' = '[
13
+ {
14
+ "name": "c1",
15
+ "paused": true,
16
+ "transport": {
17
+ "name": "datagen",
18
+ "config": {"plan": [{ "rate": 1, "fields": { "num": { "range": [0, 10], "strategy": "uniform" } } }]}
19
+ }
20
+ }
21
+ ]'
22
+ );
23
+ """
24
+
25
+ name = "test_connector_orchestration"
26
+
27
+ pipeline = PipelineBuilder(TEST_CLIENT, name, sql=sql).create_or_replace()
28
+ pipeline.start()
29
+
30
+ pipeline.resume_connector("numbers", "c1")
31
+ stats = TEST_CLIENT.get_pipeline_stats(name)
32
+ c1_status = next(
33
+ item["paused"]
34
+ for item in stats["inputs"]
35
+ if item["endpoint_name"] == "numbers.c1"
36
+ )
37
+ assert not c1_status
38
+
39
+ pipeline.pause_connector("numbers", "c1")
40
+ stats = TEST_CLIENT.get_pipeline_stats(name)
41
+ c2_status = next(
42
+ item["paused"]
43
+ for item in stats["inputs"]
44
+ if item["endpoint_name"] == "numbers.c1"
45
+ )
46
+ assert c2_status
47
+
48
+ pipeline.stop(force=True)
49
+ pipeline.clear_storage()
50
+
51
+
52
+ if __name__ == "__main__":
53
+ unittest.main()