Skip to content

Commit 1cbd3a8

Browse files
authored
Extract Interface from MockContext and fix availability of some Context functions (#8)
- Extract interface UDFContext from MockContext - Add documentation to UDFContext - Fix availability of get_dataframe() and size() in the UDFContext depending on the UDF Type - Restrict the GitHub Actions to python 3.6, because we currently only provide 3.6 in the UDFs
1 parent 339b85e commit 1cbd3a8

File tree

5 files changed

+63
-12
lines changed

5 files changed

+63
-12
lines changed

.github/workflows/check_setup_py.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
strategy:
88
fail-fast: false
99
matrix:
10-
python-version: [3.6, 3.7, 3.8]
10+
python-version: [3.6]
1111
runs-on: ubuntu-latest
1212

1313
steps:

.github/workflows/pytest.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
strategy:
88
fail-fast: false
99
matrix:
10-
python-version: [3.6, 3.7, 3.8]
10+
python-version: [3.6]
1111
runs-on: ubuntu-latest
1212

1313
steps:

exasol_udf_mock_python/mock_context.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import itertools
21
from typing import List, Tuple, Iterator
32

43
import pandas as pd
54

65
from exasol_udf_mock_python.column import Column
76
from exasol_udf_mock_python.group import Group
87
from exasol_udf_mock_python.mock_meta_data import MockMetaData
8+
from exasol_udf_mock_python.udf_context import UDFContext
99

1010

11-
class MockContext:
11+
class MockContext(UDFContext):
1212

1313
def __init__(self, input_groups: Iterator[Group], metadata: MockMetaData):
1414
self._input_groups = input_groups
@@ -81,7 +81,7 @@ def next(self, reset:bool = False):
8181
try:
8282
new_data = next(self._iter)
8383
self._data = new_data
84-
self.validate_tuples(self._data, self._metadata.input_columns)
84+
self._validate_tuples(self._data, self._metadata.input_columns)
8585
return True
8686
except StopIteration as e:
8787
self._data = None
@@ -100,11 +100,11 @@ def emit(self, *args):
100100
else:
101101
tuples = [args]
102102
for row in tuples:
103-
self.validate_tuples(row, self._metadata.output_columns)
103+
self._validate_tuples(row, self._metadata.output_columns)
104104
self._output_group_list.extend(tuples)
105105
return
106106

107-
def validate_tuples(self, row: Tuple, columns: List[Column]):
107+
def _validate_tuples(self, row: Tuple, columns: List[Column]):
108108
if len(row) != len(columns):
109109
raise Exception(f"row {row} has not the same number of values as columns are defined")
110110
for i, column in enumerate(columns):

exasol_udf_mock_python/mock_context_run_wrapper.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,9 @@ def __init__(self, mock_context: MockContext, input_type: str, output_type: str)
2121
else:
2222
self.next = self._mock_context.next
2323
self.reset = self._mock_context.reset
24+
self.get_dataframe = self._mock_context.get_dataframe
25+
self.size = self._mock_context.size
2426

25-
def get_dataframe(self, num_rows='all', start_col=0):
26-
return self._mock_context.get_dataframe(num_rows, start_col)
2727

2828
def __getattr__(self, name):
2929
return self._mock_context.__getattr__(name)
30-
31-
def size(self):
32-
return self._mock_context.size()

exasol_udf_mock_python/udf_context.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from abc import ABCMeta, abstractmethod
2+
from typing import Union, Optional
3+
4+
import pandas as pd
5+
6+
7+
class UDFContext(metaclass=ABCMeta):
8+
"""
9+
UDFContext used to iterate over the input rows of the UDF and to emit output rows back to the database.
10+
The columns of the input rows are accessible by their name as attributes of the UDFContext, e.g. ctx.a,
11+
for the column "a".
12+
"""
13+
14+
@abstractmethod
15+
def get_dataframe(self, num_rows: Union[str, int], start_col: int = 0) -> Optional[pd.DataFrame]:
16+
"""
17+
Returns the next input rows as a pandas dataframe. This function is only available for SET UDFs.
18+
:param num_rows: either the string "all", or the number of rows to return as int
19+
:param start_col: determines from which column on the dataframe contains columns
20+
:return: A pandas Dataframe or None, if there are now more rows
21+
"""
22+
pass
23+
24+
@abstractmethod
25+
def next(self, reset: bool = False) -> bool:
26+
"""
27+
Advances the Context by one row. This function is only available for SET UDFs.
28+
:param reset: Resets the context. After the reset the context stays at the first row
29+
:return: True, if the Context advanced by one row, False if the Context were already at the last row
30+
"""
31+
pass
32+
33+
@abstractmethod
34+
def size(self) -> int:
35+
"""
36+
Returns the number of input rows. This function is only available for SET UDFs.
37+
:return:
38+
"""
39+
pass
40+
41+
@abstractmethod
42+
def reset(self):
43+
"""
44+
Resets the context. After the reset the context stays at the first row. This function is only available for SET UDFs.
45+
"""
46+
pass
47+
48+
@abstractmethod
49+
def emit(self, *args):
50+
"""
51+
Emits output rows to the database. This function is only available for EMITS UDFs.
52+
:param args: Either, one argument per output column or a single pandas DataFrame
53+
"""
54+
pass

0 commit comments

Comments
 (0)