Skip to content

Commit 9a0587e

Browse files
varshaparthaylu4nm3lu4nm3Yee Hing Tong
authored
Add support for the new Presto task (#89)
* AVSW-41872: Extend the Flyte SDK with a handler for the new task * Changs to presto object type * coding session 1 * remaining changes & cleanup * PR feedback * prefix implicits with __ * small stuff * move the schema_type call into constructor? * override add_inputs * reverting schema feedback * bump version * changes Co-authored-by: lu4nm3 <lmedina@lyft.com> Co-authored-by: Luis Medina <3936213+lu4nm3@users.noreply.github.com> Co-authored-by: Yee Hing Tong <ytong@lyft.com>
1 parent bb733a8 commit 9a0587e

9 files changed

Lines changed: 281 additions & 13 deletions

File tree

flytekit/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
from __future__ import absolute_import
22
import flytekit.plugins
33

4-
__version__ = '0.6.0b5'
4+
__version__ = '0.6.0b6'

flytekit/common/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class SdkTaskType(object):
2020
HIVE_JOB = "hive"
2121
SIDECAR_TASK = "sidecar"
2222
SENSOR_TASK = "sensor-task"
23-
23+
PRESTO_TASK = "presto"
2424

2525
GLOBAL_INPUT_NODE_ID = ''
2626

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
from __future__ import absolute_import
2+
3+
from google.protobuf.json_format import MessageToDict as _MessageToDict
4+
from flytekit import __version__
5+
6+
from flytekit.common import constants as _constants
7+
from flytekit.common.tasks import task as _base_task
8+
from flytekit.models import (
9+
interface as _interface_model
10+
)
11+
from flytekit.models import literals as _literals, types as _types, \
12+
task as _task_model
13+
14+
from flytekit.common import interface as _interface
15+
import datetime as _datetime
16+
from flytekit.models import presto as _presto_models
17+
from flytekit.common.exceptions.user import \
18+
FlyteValueException as _FlyteValueException
19+
from flytekit.common.exceptions import scopes as _exception_scopes
20+
21+
22+
class SdkPrestoTask(_base_task.SdkTask):
23+
"""
24+
This class includes the logic for building a task that executes as a Presto task.
25+
"""
26+
27+
def __init__(
28+
self,
29+
statement,
30+
output_schema,
31+
routing_group=None,
32+
catalog=None,
33+
schema=None,
34+
task_inputs=None,
35+
interruptible=False,
36+
discoverable=False,
37+
discovery_version=None,
38+
retries=1,
39+
timeout=None,
40+
):
41+
"""
42+
:param Text statement: Presto query specification
43+
:param flytekit.common.types.schema.Schema output_schema: Schema that represents that data queried from Presto
44+
:param Text routing_group: The routing group that a Presto query should be sent to for the given environment
45+
:param Text catalog: The catalog to set for the given Presto query
46+
:param Text schema: The schema to set for the given Presto query
47+
:param dict[Text,flytekit.common.types.base_sdk_types.FlyteSdkType] task_inputs: Optional inputs to the Presto task
48+
:param bool discoverable:
49+
:param Text discovery_version: String describing the version for task discovery purposes
50+
:param int retries: Number of retries to attempt
51+
:param datetime.timedelta timeout:
52+
"""
53+
54+
# Set as class fields which are used down below to configure implicit
55+
# parameters
56+
self._routing_group = routing_group or ""
57+
self._catalog = catalog or ""
58+
self._schema = schema or ""
59+
60+
metadata = _task_model.TaskMetadata(
61+
discoverable,
62+
# This needs to have the proper version reflected in it
63+
_task_model.RuntimeMetadata(
64+
_task_model.RuntimeMetadata.RuntimeType.FLYTE_SDK, __version__,
65+
"python"),
66+
timeout or _datetime.timedelta(seconds=0),
67+
_literals.RetryStrategy(retries),
68+
interruptible,
69+
discovery_version,
70+
"This is deprecated!"
71+
)
72+
73+
presto_query = _presto_models.PrestoQuery(
74+
routing_group=routing_group or "",
75+
catalog=catalog or "",
76+
schema=schema or "",
77+
statement=statement
78+
)
79+
80+
# Here we set the routing_group, catalog, and schema as implicit
81+
# parameters for caching purposes
82+
i = _interface.TypedInterface(
83+
{
84+
"__implicit_routing_group": _interface_model.Variable(
85+
type=_types.LiteralType(simple=_types.SimpleType.STRING),
86+
description="The routing group set as an implicit input"
87+
),
88+
"__implicit_catalog": _interface_model.Variable(
89+
type=_types.LiteralType(simple=_types.SimpleType.STRING),
90+
description="The catalog set as an implicit input"
91+
),
92+
"__implicit_schema": _interface_model.Variable(
93+
type=_types.LiteralType(simple=_types.SimpleType.STRING),
94+
description="The schema set as an implicit input"
95+
)
96+
},
97+
{
98+
# Set the schema for the Presto query as an output
99+
"results": _interface_model.Variable(
100+
type=_types.LiteralType(schema=output_schema.schema_type),
101+
description="The schema for the Presto query"
102+
)
103+
})
104+
105+
super(SdkPrestoTask, self).__init__(
106+
_constants.SdkTaskType.PRESTO_TASK,
107+
metadata,
108+
i,
109+
_MessageToDict(presto_query.to_flyte_idl()),
110+
)
111+
112+
# Set user provided inputs
113+
task_inputs(self)
114+
115+
# Override method in order to set the implicit inputs
116+
def __call__(self, *args, **kwargs):
117+
kwargs["__implicit_routing_group"] = self.routing_group
118+
kwargs["__implicit_catalog"] = self.catalog
119+
kwargs["__implicit_schema"] = self.schema
120+
121+
return super(SdkPrestoTask, self).__call__(
122+
*args, **kwargs
123+
)
124+
125+
@_exception_scopes.system_entry_point
126+
def add_inputs(self, inputs):
127+
"""
128+
Adds the inputs to this task. This can be called multiple times, but it will fail if an input with a given
129+
name is added more than once, a name collides with an output, or if the name doesn't exist as an arg name in
130+
the wrapped function.
131+
:param dict[Text, flytekit.models.interface.Variable] inputs: names and variables
132+
"""
133+
self._validate_inputs(inputs)
134+
self.interface.inputs.update(inputs)
135+
136+
@property
137+
def routing_group(self):
138+
"""
139+
The routing group that a Presto query should be sent to for the given environment
140+
:rtype: Text
141+
"""
142+
return self._routing_group
143+
144+
@property
145+
def catalog(self):
146+
"""
147+
The catalog to set for the given Presto query
148+
:rtype: Text
149+
"""
150+
return self._catalog
151+
152+
@property
153+
def schema(self):
154+
"""
155+
The schema to set for the given Presto query
156+
:rtype: Text
157+
"""
158+
return self._schema

flytekit/common/tasks/sdk_runnable.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,17 @@ def __init__(
235235
_banned_inputs = {}
236236
_banned_outputs = {}
237237

238+
@_exception_scopes.system_entry_point
239+
def add_inputs(self, inputs):
240+
"""
241+
Adds the inputs to this task. This can be called multiple times, but it will fail if an input with a given
242+
name is added more than once, a name collides with an output, or if the name doesn't exist as an arg name in
243+
the wrapped function.
244+
:param dict[Text, flytekit.models.interface.Variable] inputs: names and variables
245+
"""
246+
self._validate_inputs(inputs)
247+
self.interface.inputs.update(inputs)
248+
238249
@classmethod
239250
def promote_from_model(cls, base_model):
240251
# TODO: If the task exists in this container, we should be able to retrieve it.

flytekit/common/tasks/task.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66

77
from flytekit.common import interface as _interfaces, nodes as _nodes, sdk_bases as _sdk_bases
88
from flytekit.common.core import identifier as _identifier
9-
from flytekit.common.exceptions import user as _user_exceptions, scopes as _exception_scopes
9+
from flytekit.common.exceptions import scopes as _exception_scopes
1010
from flytekit.common.mixins import registerable as _registerable, hash as _hash_mixin
1111
from flytekit.configuration import internal as _internal_config
1212
from flytekit.engines import loader as _engine_loader
1313
from flytekit.models import common as _common_model, task as _task_model
1414
from flytekit.models.core import workflow as _workflow_model, identifier as _identifier_model
15+
from flytekit.common.exceptions import user as _user_exceptions
1516

1617

1718
class SdkTask(
@@ -189,14 +190,7 @@ def validate(self):
189190

190191
@_exception_scopes.system_entry_point
191192
def add_inputs(self, inputs):
192-
"""
193-
Adds the inputs to this task. This can be called multiple times, but it will fail if an input with a given
194-
name is added more than once, a name collides with an output, or if the name doesn't exist as an arg name in
195-
the wrapped function.
196-
:param dict[Text, flytekit.models.interface.Variable] inputs: names and variables
197-
"""
198-
self._validate_inputs(inputs)
199-
self.interface.inputs.update(inputs)
193+
raise _user_exceptions.FlyteUserException("You can not add inputs to this task")
200194

201195
@_exception_scopes.system_entry_point
202196
def add_outputs(self, outputs):

flytekit/models/presto.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
from __future__ import absolute_import
2+
3+
## Todo - change this to qubole_presto once Luis's PR get's merged
4+
# from flyteidl.plugins import qubole_presto as _qubole
5+
from flyteidl.plugins import presto_pb2 as _presto
6+
7+
from flytekit.models import common as _common
8+
9+
10+
class PrestoQuery(_common.FlyteIdlEntity):
11+
def __init__(self, routing_group, catalog, schema, statement):
12+
"""
13+
Initializes a new PrestoQuery.
14+
15+
:param string routing_group:
16+
:param string catalog:
17+
:param string schema:
18+
:param string statement:
19+
20+
"""
21+
self._routing_group = routing_group
22+
self._catalog = catalog
23+
self._schema = schema
24+
self._statement = statement
25+
26+
@property
27+
def routing_group(self):
28+
"""
29+
The query string.
30+
:rtype: str
31+
"""
32+
return self._routing_group
33+
34+
@property
35+
def catalog(self):
36+
"""
37+
:rtype: int
38+
"""
39+
return self._catalog
40+
41+
@property
42+
def schema(self):
43+
"""
44+
:rtype: int
45+
"""
46+
return self._schema
47+
48+
@property
49+
def statement(self):
50+
"""
51+
:rtype: int
52+
"""
53+
return self._statement
54+
55+
def to_flyte_idl(self):
56+
"""
57+
:rtype: _presto.PrestoQuery
58+
"""
59+
return _presto.PrestoQuery(
60+
routing_group=self._routing_group,
61+
catalog=self._catalog,
62+
schema=self._schema,
63+
statement=self._statement
64+
)
65+
66+
@classmethod
67+
def from_flyte_idl(cls, pb2_object):
68+
"""
69+
:param _presto.PrestoQuery pb2_object:
70+
:return: PrestoQuery
71+
"""
72+
return cls(
73+
routing_group=pb2_object.routing_group,
74+
catalog=pb2_object.catalog,
75+
schema=pb2_object.schema,
76+
statement=pb2_object.statement
77+
)

flytekit/sdk/tasks.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from flytekit.common.exceptions import user as _user_exceptions
88
from flytekit.common.tasks import sdk_runnable as _sdk_runnable_tasks, sdk_dynamic as _sdk_dynamic, \
99
spark_task as _sdk_spark_tasks, hive_task as _sdk_hive_tasks, sidecar_task as _sdk_sidecar_tasks
10+
from flytekit.common.tasks import task as _task
1011
from flytekit.common.types import helpers as _type_helpers
1112
from flytekit.models import interface as _interface_model
1213

@@ -35,7 +36,7 @@ def my_task(wf_params, in1, in2, out1, out2):
3536
"""
3637

3738
def apply_inputs_wrapper(task):
38-
if not isinstance(task, _sdk_runnable_tasks.SdkRunnableTask):
39+
if not isinstance(task, _task.SdkTask):
3940
additional_msg = \
4041
"Inputs can only be applied to a task. Did you forget the task decorator on method '{}.{}'?".format(
4142
task.__module__,

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
]
3030
},
3131
install_requires=[
32-
"flyteidl>=0.17.8,<1.0.0",
32+
"flyteidl>=0.17.9,<1.0.0",
3333
"click>=6.6,<8.0",
3434
"croniter>=0.3.20,<4.0.0",
3535
"deprecation>=2.0,<3.0",
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from __future__ import absolute_import
2+
3+
from flytekit.sdk.tasks import inputs
4+
from flytekit.sdk.types import Types
5+
from flytekit.sdk.workflow import workflow_class, Input, Output
6+
from flytekit.common.tasks.presto_task import SdkPrestoTask
7+
8+
schema = Types.Schema([("a", Types.String), ("b", Types.Integer)])
9+
10+
presto_task = SdkPrestoTask(
11+
task_inputs=inputs(ds=Types.String, rg=Types.String),
12+
statement="SELECT * FROM hive.city.fact_airport_sessions WHERE ds = '{{ .Inputs.ds}}' LIMIT 10",
13+
output_schema=schema,
14+
routing_group="{{ .Inputs.rg }}",
15+
# catalog="hive",
16+
# schema="city",
17+
)
18+
19+
20+
@workflow_class()
21+
class PrestoWorkflow(object):
22+
ds = Input(Types.String, required=True, help="Test string with no default")
23+
# routing_group = Input(Types.String, required=True, help="Test string with no default")
24+
25+
p_task = presto_task(ds=ds, rg='etl')
26+
27+
output_a = Output(p_task.outputs.results, sdk_type=schema)

0 commit comments

Comments
 (0)