Skip to content

Commit

Permalink
HPCC-30721 Fix Python examples to use Python3
Browse files Browse the repository at this point in the history
Signed-off-by: Jim DeFabia <[email protected]>
  • Loading branch information
Jim DeFabia committed Oct 31, 2023
1 parent 4c17a2c commit dda2c21
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 72 deletions.
12 changes: 6 additions & 6 deletions initfiles/examples/embed/python-catch.ecl
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
IMPORT Python;
IMPORT Python3 as Python;

/*
This example illustrates and tests the use of embedded Python
*/

// Mapping of exceptions from Python to ECL

integer testThrow(integer val) := EMBED(Python)
raise Exception('Error from Python')
INTEGER testThrow(integer val) := EMBED(Python)
raise Exception('Error from Python')
ENDEMBED;

// Can't catch an expression(only a dataset)
d := dataset([{ 1, '' }], { integer a, string m} ) : stored('nofold');
d := DATASET([{ 1, '' }], { INTEGER a, STRING m} ) : STORED('nofold');

d t := transform
d t := TRANSFORM
self.a := FAILCODE;
self.m := FAILMESSAGE;
self := [];
end;

catch(d(testThrow(a) = a), onfail(t));
CATCH(d(testThrow(a) = a), onfail(t));
2 changes: 1 addition & 1 deletion initfiles/examples/embed/python-import.ecl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
IMPORT python;
IMPORT Python3 as Python;

/*
This example illustrates a call to a Python functions defined in the Python module python_cat.py
Expand Down
72 changes: 36 additions & 36 deletions initfiles/examples/embed/python-simple.ecl
Original file line number Diff line number Diff line change
@@ -1,80 +1,80 @@
IMPORT Python;
IMPORT Python3 as Python;

/*
This example illustrates and tests the use of embedded Python
*/

// Scalar parameters and resuls

integer add1(integer val) := EMBED(Python)
val+1
INTEGER add1(INTEGER val) := EMBED(Python)
val+1
ENDEMBED;

string add2(string val) := EMBED(Python)
val+'1'
STRING add2(STRING val) := EMBED(Python)
val+'1'
ENDEMBED;

string add3(varstring val) := EMBED(Python)
val+'1'
STRING add3(VARSTRING val) := EMBED(Python)
val+'1'
ENDEMBED;

utf8 add4(utf8 val) := EMBED(Python)
val+'1'
UTF8 add4(UTF8 val) := EMBED(Python)
val+'1'
ENDEMBED;

unicode add5(unicode val) := EMBED(Python)
val+'1'
UNICODE add5(UNICODE val) := EMBED(Python)
val+'1'
ENDEMBED;

utf8 add6(utf8 val) := EMBED(Python)
return val+'1'
UTF8 add6(UTF8 val) := EMBED(Python)
return val+'1'
ENDEMBED;

unicode add7(unicode val) := EMBED(Python)
return val+'1'
UNICODE add7(UNICODE val) := EMBED(Python)
return val+'1'
ENDEMBED;

data testData(data val) := EMBED(Python)
val[0] = val[0] + 1
return val
DATA testData(DATA val) := EMBED(Python)
val[0] = val[0] + 1
return val
ENDEMBED;

// Sets in ECL map to Python lists

set of integer testSet(set of integer val) := EMBED(Python)
return sorted(val)
SET OF INTEGER testSet(SET OF INTEGER val) := EMBED(Python)
return sorted(val)
ENDEMBED;

set of string testSet2(set of string val) := EMBED(Python)
return sorted(val)
SET OF STRING testSet2(SET OF STRING val) := EMBED(Python)
return sorted(val)
ENDEMBED;

set of string testSet3(set of string8 val) := EMBED(Python)
return sorted(val)
SET OF STRING testSet3(SET OF STRING8 val) := EMBED(Python)
return sorted(val)
ENDEMBED;

set of utf8 testSet4(set of utf8 val) := EMBED(Python)
return sorted(val)
SET OF UTF8 testSet4(SET OF UTF8 val) := EMBED(Python)
return sorted(val)
ENDEMBED;

set of varstring testSet5(set of varstring val) := EMBED(Python)
return sorted(val)
SET OF VARSTRING testSet5(SET OF VARSTRING val) := EMBED(Python)
return sorted(val)
ENDEMBED;

set of varstring8 testSet6(set of varstring8 val) := EMBED(Python)
return sorted(val)
SET OF VARSTRING8 testSet6(SET OF VARSTRING8 val) := EMBED(Python)
return sorted(val)
ENDEMBED;

set of unicode testSet7(set of unicode val) := EMBED(Python)
return sorted(val)
SET OF UNICODE testSet7(SET OF UNICODE val) := EMBED(Python)
return sorted(val)
ENDEMBED;

set of unicode8 testSet8(set of unicode8 val) := EMBED(Python)
return sorted(val)
SET OF UNICODE8 testSet8(SET OF UNICODE8 val) := EMBED(Python)
return sorted(val)
ENDEMBED;

set of data testSet9(set of data val) := EMBED(Python)
return val
SET OF DATA testSet9(SET OF DATA val) := EMBED(Python)
return val
ENDEMBED;

// Now run the tests
Expand Down
4 changes: 2 additions & 2 deletions initfiles/examples/embed/python-simple2.ecl
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import python;
IMPORT Python3 as Python;
/*
This example illustrates and tests the use of embedded Python.
In this example the python that is embedded is more complex, including a definition of a function
*/


string anagram(string word) := EMBED(Python)
STRING anagram(string word) := EMBED(Python)
def anagram(w):
if word == 'cat':
return 'act'
Expand Down
54 changes: 27 additions & 27 deletions initfiles/examples/embed/python-stream.ecl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
IMPORT Python;
IMPORT Python3 as Python;

/*
This example illustrates and tests the use of embedded Python.
Expand All @@ -9,17 +9,17 @@ IMPORT Python;
// These are the record structures we will be returning - note the child records, datasets and dictionaries in it

childrec := RECORD
string name => unsigned value;
STRING name => UNSIGNED value;
END;

eclRecord := RECORD
STRING name1;
STRING10 name2;
LINKCOUNTED DATASET(childrec) childnames;
LINKCOUNTED DICTIONARY(childrec) childdict{linkcounted};
LINKCOUNTED DICTIONARY(childrec) childdict{LINKCOUNTED};
childrec r;
unsigned1 val1;
integer1 val2;
UNSIGNED1 val1;
INTEGER1 val2;
UTF8 u1;
UNICODE u2;
UNICODE8 u3;
Expand All @@ -30,103 +30,103 @@ eclRecord := RECORD
END;

namerec := RECORD
string name;
STRING name;
END;

namerec2 := RECORD
string name;
string name2;
STRING name;
STRING name2;
END;

// To return a dataset, we can return a list of tuples, each one correponding to a field in the resulting ECL record
// In this example, the fields are mapped by position
// Just to spice things up we proved a couple of parameters too

dataset(eclRecord) streamedNames(data d, utf8 u) := EMBED(Python)
DATASET(eclRecord) streamedNames(DATA d, utf8 u) := EMBED(Python)
return [ \
("Gavin", "Halliday", [("a", 1),("b", 2),("c", 3)], [("aa", 11)], ("aaa", 111), 250, -1, U'là', U'là', U'là', 0x01000000, d, False, {"1","2"}), \
("John", "Smith", [], [], ("c", 3), 250, -1, U'là', U'là', u, 0x02000000, d, True, []) \
]
ENDEMBED;

output(streamedNames(d'AA', u'là'));
OUTPUT(streamedNames(d'AA', u'là'));

// We can also return a dataset by using a Python generator, which will be lazy-evaluated as the records are required by ECL code...

dataset(childrec) testGenerator(unsigned lim) := EMBED(Python)
DATASET(childrec) testGenerator(unsigned lim) := EMBED(Python)
num = 0
while num < lim:
yield ("Generated", num)
num += 1
ENDEMBED;

output (testGenerator(10));
OUTPUT (testGenerator(10));

// If the returned tuples are namedtuples, we map fields by name rather than by position

// Test use of Python named tuple...

dataset(childrec) testNamedTuples() := EMBED(Python)
DATASET(childrec) testNamedTuples() := EMBED(Python)
import collections
ChildRec = collections.namedtuple("childrec", "value, name") # Note - order is reverse of childrec - but works as we get fields by name
c1 = ChildRec(1, "name1")
c2 = ChildRec(name="name2", value=2)
return [ c1, c2 ]
ENDEMBED;

output(testNamedTuples());
OUTPUT(testNamedTuples());

// To return a record, just return a tuple (or namedtuple)

childrec testRecord(integer value, string s) := EMBED(Python)
return (s, value)
ENDEMBED;

output(testRecord(1,'Hello').value);
output(testRecord(1,'Hello').name);
OUTPUT(testRecord(1,'Hello').value);
OUTPUT(testRecord(1,'Hello').name);

// If the record has a single field, you don't need to put the field into a tuple...

dataset(namerec) testMissingTuple1(unsigned lim) := EMBED(Python)
DATASET(namerec) testMissingTuple1(unsigned lim) := EMBED(Python)
return [ '1', '2', '3' ]
ENDEMBED;
output (testMissingTuple1(10));
OUTPUT (testMissingTuple1(10));

// ... but you can if you want

dataset(namerec) testMissingTuple2(unsigned lim) := EMBED(Python)
DATASET(namerec) testMissingTuple2(unsigned lim) := EMBED(Python)
return [ ('1'), ('2'), ('3') ]
ENDEMBED;
output (testMissingTuple2(10));
OUTPUT (testMissingTuple2(10));

// You can define a transform in Python, using a function that returns a record (i.e. a Python tuple)
// Note that the tuple we pass to Python is a namedtuple

transform(childrec) testTransform(namerec inrec, unsigned c) := EMBED(Python)
TRANSFORM(childrec) testTransform(namerec inrec, unsigned c) := EMBED(Python)
return (inrec.name, c)
ENDEMBED;

d := dataset([{'Richard'},{'Gavin'}], namerec);
d := DATASET([{'Richard'},{'Gavin'}], namerec);

output(project(d, testTransform(LEFT, COUNTER)));
OUTPUT(PROJECT(d, testTransform(LEFT, COUNTER)));

// Most transforms take a record as the input, but it's not a requirement

transform(childrec) testTransformNoRow(unsigned lim) := EMBED(Python)
TRANSFORM(childrec) testTransformNoRow(unsigned lim) := EMBED(Python)
return ("Hello", lim)
ENDEMBED;

output(row(testTransformNoRow(10)));
OUTPUT(ROW(testTransformNoRow(10)));

// When passing datasets to Python, we get an iterator of named tuples
// They are actually implemented as generators, meaning they are lazy-evaluated

names := DATASET([{'Richard'}, {'James'}, {'Andrew'}], namerec);

string datasetAsIterator(dataset(namerec) input) := EMBED(Python)
STRING datasetAsIterator(DATASET(namerec) input) := EMBED(Python)
s = ''
for n in input:
s = s + ' ' + n.name
return s;
ENDEMBED;
output(datasetAsIterator(names));
OUTPUT(datasetAsIterator(names));

0 comments on commit dda2c21

Please sign in to comment.