flytekitplugins-perian-job 1.12.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.
@@ -0,0 +1,92 @@
1
+ Metadata-Version: 2.1
2
+ Name: flytekitplugins-perian_job
3
+ Version: 1.12.0
4
+ Summary: Flyte agent for Perian Job Platform (perian.io)
5
+ Author: Omar Tarabai
6
+ Author-email: otarabai@perian.io
7
+ License: apache2
8
+ Classifier: Intended Audience :: Science/Research
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: Apache Software License
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Topic :: Scientific/Engineering
16
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
17
+ Classifier: Topic :: Software Development
18
+ Classifier: Topic :: Software Development :: Libraries
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: >=3.8
21
+ Description-Content-Type: text/markdown
22
+
23
+ # Flytekit Perian Job Platform Plugin
24
+
25
+ Flyte Agent plugin for executing Flyte tasks on Perian Job Platform (perian.io).
26
+
27
+ Perian Job Platform is still in closed beta. Contact support@perian.io if you are interested in trying it out.
28
+
29
+ To install the plugin, run the following command:
30
+
31
+ ```bash
32
+ pip install flytekitplugins-perian-job
33
+ ```
34
+
35
+ ## Getting Started
36
+
37
+ This plugin allows executing `PythonFunctionTask` on Perian.
38
+
39
+ An [ImageSpec](https://docs.flyte.org/en/latest/user_guide/customizing_dependencies/imagespec.html) need to be built with the perian agent plugin installed.
40
+
41
+ ### Parameters
42
+
43
+ The following parameters can be used to set the requirements for the Perian task. If any of the requirements are skipped, it is replaced with the cheapest option. At least one requirement value should be set.
44
+ * `cores`: Number of CPU cores
45
+ * `memory`: Amount of memory in GB
46
+ * `accelerators`: Number of accelerators
47
+ * `accelerator_type`: Type of accelerator (e.g. 'A100'). For a full list of supported accelerators, use the perian CLI list-accelerators command.
48
+ * `country_code`: Country code to run the job in (e.g. 'DE')
49
+
50
+ ### Credentials
51
+
52
+ The following [secrets](https://docs.flyte.org/en/latest/user_guide/productionizing/secrets.html) are required to be defined for the agent server:
53
+ * Perian credentials:
54
+ * `perian_organization`
55
+ * `perian_token`
56
+ * AWS credentials for accessing the Flyte storage bucket. You might need to create long-lived credentials to avoid expiry when running tasks. These credentials are never logged by Perian and are stored only until it is used, then immediately deleted:
57
+ * `aws_access_key_id`
58
+ * `aws_secret_access_key`
59
+ * (Optional) Custom docker registry for pulling the Flyte image:
60
+ * `docker_registry_url`
61
+ * `docker_registry_username`
62
+ * `docker_registry_password`
63
+
64
+ ### Example
65
+
66
+ `example.py` workflow example:
67
+ ```python
68
+ from flytekit import ImageSpec, task, workflow
69
+ from flytekitplugins.perian_job import PerianConfig
70
+
71
+ image_spec = ImageSpec(
72
+ name="flyte-test",
73
+ registry="my-registry",
74
+ python_version="3.11",
75
+ apt_packages=["wget", "curl", "git"],
76
+ packages=[
77
+ "flytekitplugins-perian-job",
78
+ ],
79
+ )
80
+
81
+ @task(container_image=image_spec,
82
+ task_config=PerianConfig(
83
+ accelerators=1,
84
+ accelerator_type="A100",
85
+ ))
86
+ def perian_hello(name: str) -> str:
87
+ return f"hello {name}!"
88
+
89
+ @workflow
90
+ def my_wf(name: str = "world") -> str:
91
+ return perian_hello(name=name)
92
+ ```
@@ -0,0 +1,70 @@
1
+ # Flytekit Perian Job Platform Plugin
2
+
3
+ Flyte Agent plugin for executing Flyte tasks on Perian Job Platform (perian.io).
4
+
5
+ Perian Job Platform is still in closed beta. Contact support@perian.io if you are interested in trying it out.
6
+
7
+ To install the plugin, run the following command:
8
+
9
+ ```bash
10
+ pip install flytekitplugins-perian-job
11
+ ```
12
+
13
+ ## Getting Started
14
+
15
+ This plugin allows executing `PythonFunctionTask` on Perian.
16
+
17
+ An [ImageSpec](https://docs.flyte.org/en/latest/user_guide/customizing_dependencies/imagespec.html) need to be built with the perian agent plugin installed.
18
+
19
+ ### Parameters
20
+
21
+ The following parameters can be used to set the requirements for the Perian task. If any of the requirements are skipped, it is replaced with the cheapest option. At least one requirement value should be set.
22
+ * `cores`: Number of CPU cores
23
+ * `memory`: Amount of memory in GB
24
+ * `accelerators`: Number of accelerators
25
+ * `accelerator_type`: Type of accelerator (e.g. 'A100'). For a full list of supported accelerators, use the perian CLI list-accelerators command.
26
+ * `country_code`: Country code to run the job in (e.g. 'DE')
27
+
28
+ ### Credentials
29
+
30
+ The following [secrets](https://docs.flyte.org/en/latest/user_guide/productionizing/secrets.html) are required to be defined for the agent server:
31
+ * Perian credentials:
32
+ * `perian_organization`
33
+ * `perian_token`
34
+ * AWS credentials for accessing the Flyte storage bucket. You might need to create long-lived credentials to avoid expiry when running tasks. These credentials are never logged by Perian and are stored only until it is used, then immediately deleted:
35
+ * `aws_access_key_id`
36
+ * `aws_secret_access_key`
37
+ * (Optional) Custom docker registry for pulling the Flyte image:
38
+ * `docker_registry_url`
39
+ * `docker_registry_username`
40
+ * `docker_registry_password`
41
+
42
+ ### Example
43
+
44
+ `example.py` workflow example:
45
+ ```python
46
+ from flytekit import ImageSpec, task, workflow
47
+ from flytekitplugins.perian_job import PerianConfig
48
+
49
+ image_spec = ImageSpec(
50
+ name="flyte-test",
51
+ registry="my-registry",
52
+ python_version="3.11",
53
+ apt_packages=["wget", "curl", "git"],
54
+ packages=[
55
+ "flytekitplugins-perian-job",
56
+ ],
57
+ )
58
+
59
+ @task(container_image=image_spec,
60
+ task_config=PerianConfig(
61
+ accelerators=1,
62
+ accelerator_type="A100",
63
+ ))
64
+ def perian_hello(name: str) -> str:
65
+ return f"hello {name}!"
66
+
67
+ @workflow
68
+ def my_wf(name: str = "world") -> str:
69
+ return perian_hello(name=name)
70
+ ```
@@ -0,0 +1,2 @@
1
+ from .agent import PerianAgent
2
+ from .task import PerianConfig, PerianTask
@@ -0,0 +1,200 @@
1
+ import shlex
2
+ from dataclasses import dataclass
3
+ from typing import Optional
4
+
5
+ from flyteidl.core.execution_pb2 import TaskExecution
6
+ from perian import (
7
+ AcceleratorQueryInput,
8
+ ApiClient,
9
+ Configuration,
10
+ CpuQueryInput,
11
+ CreateJobRequest,
12
+ DockerRegistryCredentials,
13
+ DockerRunParameters,
14
+ InstanceTypeQueryInput,
15
+ JobApi,
16
+ JobStatus,
17
+ MemoryQueryInput,
18
+ Name,
19
+ ProviderQueryInput,
20
+ RegionQueryInput,
21
+ Size,
22
+ )
23
+
24
+ from flytekit import current_context
25
+ from flytekit.exceptions.base import FlyteException
26
+ from flytekit.exceptions.user import FlyteUserException
27
+ from flytekit.extend.backend.base_agent import AgentRegistry, AsyncAgentBase, Resource, ResourceMeta
28
+ from flytekit.loggers import logger
29
+ from flytekit.models.literals import LiteralMap
30
+ from flytekit.models.task import TaskTemplate
31
+
32
+ PERIAN_API_URL = "https://api.perian.cloud"
33
+
34
+
35
+ @dataclass
36
+ class PerianMetadata(ResourceMeta):
37
+ """Metadata for Perian jobs"""
38
+
39
+ job_id: str
40
+
41
+
42
+ class PerianAgent(AsyncAgentBase):
43
+ """Flyte Agent for executing tasks on Perian"""
44
+
45
+ name = "Perian Agent"
46
+
47
+ def __init__(self):
48
+ logger.info("Initializing Perian agent")
49
+ super().__init__(task_type_name="perian_task", metadata_type=PerianMetadata)
50
+
51
+ async def create(
52
+ self,
53
+ task_template: TaskTemplate,
54
+ inputs: Optional[LiteralMap],
55
+ output_prefix: Optional[str],
56
+ **kwargs,
57
+ ) -> PerianMetadata:
58
+ logger.info("Creating new Perian job")
59
+ logger.debug("Task template: %s", task_template.__dict__)
60
+
61
+ config = Configuration(host=PERIAN_API_URL)
62
+ job_request = self._build_create_job_request(task_template)
63
+ with ApiClient(config) as api_client:
64
+ api_instance = JobApi(api_client)
65
+ response = api_instance.create_job(
66
+ create_job_request=job_request,
67
+ _headers=self._build_headers(),
68
+ )
69
+ if response.status_code != 200:
70
+ raise FlyteException(f"Failed to create Perian job: {response.text}")
71
+
72
+ return PerianMetadata(job_id=response.id)
73
+
74
+ def get(self, resource_meta: PerianMetadata, **kwargs) -> Resource:
75
+ job_id = resource_meta.job_id
76
+ logger.info("Getting Perian job status: %s", job_id)
77
+ config = Configuration(host=PERIAN_API_URL)
78
+ with ApiClient(config) as api_client:
79
+ api_instance = JobApi(api_client)
80
+ response = api_instance.get_job_by_id(
81
+ job_id=str(job_id),
82
+ _headers=self._build_headers(),
83
+ )
84
+ if response.status_code != 200:
85
+ raise FlyteException(f"Failed to get Perian job status: {response.text}")
86
+ if not response.jobs:
87
+ raise FlyteException(f"Perian job not found: {job_id}")
88
+ job = response.jobs[0]
89
+
90
+ return Resource(
91
+ phase=self._perian_job_status_to_flyte_phase(job.status),
92
+ message=job.logs,
93
+ )
94
+
95
+ def delete(self, resource_meta: PerianMetadata, **kwargs):
96
+ job_id = resource_meta.job_id
97
+ logger.info("Cancelling Perian job: %s", job_id)
98
+ config = Configuration(host=PERIAN_API_URL)
99
+ with ApiClient(config) as api_client:
100
+ api_instance = JobApi(api_client)
101
+ response = api_instance.cancel_job(
102
+ job_id=str(job_id),
103
+ _headers=self._build_headers(),
104
+ )
105
+ if response.status_code != 200:
106
+ raise FlyteException(f"Failed to cancel Perian job: {response.text}")
107
+
108
+ def _build_create_job_request(self, task_template: TaskTemplate) -> CreateJobRequest:
109
+ params = task_template.custom
110
+ secrets = current_context().secrets
111
+
112
+ # Build instance type requirements
113
+ reqs = InstanceTypeQueryInput()
114
+ if params.get("cores"):
115
+ reqs.cpu = CpuQueryInput(cores=int(params["cores"]))
116
+ if params.get("memory"):
117
+ reqs.ram = MemoryQueryInput(size=Size(params["memory"]))
118
+ if any([params.get("accelerators"), params.get("accelerator_type")]):
119
+ reqs.accelerator = AcceleratorQueryInput()
120
+ if params.get("accelerators"):
121
+ reqs.accelerator.no = int(params["accelerators"])
122
+ if params.get("accelerator_type"):
123
+ reqs.accelerator.name = Name(params["accelerator_type"])
124
+ if params.get("country_code"):
125
+ reqs.region = RegionQueryInput(location=params["country_code"])
126
+ if params.get("provider"):
127
+ reqs.provider = ProviderQueryInput(name_short=params["provider"])
128
+
129
+ docker_run = DockerRunParameters()
130
+ # Credentials to the Flyte storage S3 bucket need to be passed to the Perian job.
131
+ aws_access_key_id = secrets.get("aws_access_key_id")
132
+ aws_secret_access_key = secrets.get("aws_secret_access_key")
133
+ if not aws_access_key_id or not aws_secret_access_key:
134
+ raise FlyteUserException(
135
+ "AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY for the Flyte storage bucket "
136
+ "must be provided in the secrets"
137
+ )
138
+ docker_run.env_variables = {
139
+ "AWS_ACCESS_KEY_ID": aws_access_key_id,
140
+ "AWS_SECRET_ACCESS_KEY": aws_secret_access_key,
141
+ }
142
+
143
+ docker_registry = None
144
+ try:
145
+ dr_url = secrets.get("docker_registry_url")
146
+ dr_username = secrets.get("docker_registry_username")
147
+ dr_password = secrets.get("docker_registry_password")
148
+ if any([dr_url, dr_username, dr_password]):
149
+ docker_registry = DockerRegistryCredentials(
150
+ url=dr_url,
151
+ username=dr_username,
152
+ password=dr_password,
153
+ )
154
+ except ValueError:
155
+ pass
156
+
157
+ container = task_template.container
158
+ if ":" in container.image:
159
+ docker_run.image_name, docker_run.image_tag = container.image.rsplit(":", 1)
160
+ else:
161
+ docker_run.image_name = container.image
162
+ if container.args:
163
+ docker_run.command = shlex.join(container.args)
164
+
165
+ return CreateJobRequest(
166
+ auto_failover_instance_type=True,
167
+ requirements=reqs,
168
+ docker_run_parameters=docker_run,
169
+ docker_registry_credentials=docker_registry,
170
+ )
171
+
172
+ def _build_headers(self) -> dict:
173
+ secrets = current_context().secrets
174
+ org = secrets.get("perian_organization")
175
+ token = secrets.get("perian_token")
176
+ if not org or not token:
177
+ raise FlyteUserException(
178
+ "perian_organization and perian_token must be provided in the secrets")
179
+ return {
180
+ "X-PERIAN-AUTH-ORG": org,
181
+ "Authorization": "Bearer " + token,
182
+ }
183
+
184
+ def _perian_job_status_to_flyte_phase(self, status: JobStatus) -> TaskExecution.Phase:
185
+ status_map = {
186
+ JobStatus.QUEUED: TaskExecution.QUEUED,
187
+ JobStatus.INITIALIZING: TaskExecution.INITIALIZING,
188
+ JobStatus.RUNNING: TaskExecution.RUNNING,
189
+ JobStatus.DONE: TaskExecution.SUCCEEDED,
190
+ JobStatus.SERVERERROR: TaskExecution.FAILED,
191
+ JobStatus.USERERROR: TaskExecution.FAILED,
192
+ JobStatus.CANCELLED: TaskExecution.ABORTED,
193
+ }
194
+ if status == JobStatus.UNDEFINED:
195
+ raise FlyteException("Undefined Perian job status")
196
+ return status_map[status]
197
+
198
+
199
+ # To register the Perian agent
200
+ AgentRegistry.register(PerianAgent())
@@ -0,0 +1,98 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, Callable, Dict, Optional, Union
3
+
4
+ from google.protobuf import json_format
5
+ from google.protobuf.struct_pb2 import Struct
6
+
7
+ from flytekit import FlyteContextManager, PythonFunctionTask, logger
8
+ from flytekit.configuration import SerializationSettings
9
+ from flytekit.exceptions.user import FlyteUserException
10
+ from flytekit.extend import TaskPlugins
11
+ from flytekit.extend.backend.base_agent import AsyncAgentExecutorMixin
12
+ from flytekit.image_spec import ImageSpec
13
+
14
+
15
+ @dataclass
16
+ class PerianConfig:
17
+ """Used to configure a Perian Task"""
18
+
19
+ # Number of CPU cores
20
+ cores: Optional[int] = None
21
+ # Amount of memory in GB
22
+ memory: Optional[int] = None
23
+ # Number of accelerators
24
+ accelerators: Optional[int] = None
25
+ # Type of accelerator (e.g. 'A100')
26
+ # For a full list of supported accelerators, use the perian CLI list-accelerators command
27
+ accelerator_type: Optional[str] = None
28
+ # Country code to run the job in (e.g. 'DE')
29
+ country_code: Optional[str] = None
30
+ # Cloud provider to run the job on
31
+ provider: Optional[str] = None
32
+
33
+
34
+ class PerianTask(AsyncAgentExecutorMixin, PythonFunctionTask):
35
+ """A special task type for running tasks on Perian Job Platform (perian.io)"""
36
+
37
+ _TASK_TYPE = "perian_task"
38
+
39
+ def __init__(
40
+ self,
41
+ task_config: Optional[PerianConfig],
42
+ task_function: Callable,
43
+ container_image: Optional[Union[str, ImageSpec]] = None,
44
+ **kwargs,
45
+ ):
46
+ super().__init__(
47
+ task_config=task_config,
48
+ task_function=task_function,
49
+ container_image=container_image,
50
+ task_type=self._TASK_TYPE,
51
+ **kwargs,
52
+ )
53
+
54
+ def execute(self, **kwargs) -> Any:
55
+ if isinstance(self.task_config, PerianConfig):
56
+ # Use the Perian agent to run it by default.
57
+ try:
58
+ ctx = FlyteContextManager.current_context()
59
+ if not ctx.file_access.is_remote(ctx.file_access.raw_output_prefix):
60
+ raise ValueError(
61
+ "To submit a Perian job locally,"
62
+ " please set --raw-output-data-prefix to a remote path. e.g. s3://, gcs//, etc."
63
+ )
64
+ if ctx.execution_state and ctx.execution_state.is_local_execution():
65
+ return AsyncAgentExecutorMixin.execute(self, **kwargs)
66
+ except Exception as e:
67
+ logger.error("Agent failed to run the task with error: %s", e)
68
+ raise
69
+ return PythonFunctionTask.execute(self, **kwargs)
70
+
71
+ def get_custom(self, settings: SerializationSettings) -> Dict[str, Any]:
72
+ """
73
+ Return plugin-specific data as a serializable dictionary.
74
+ """
75
+ config = {
76
+ "cores": self.task_config.cores,
77
+ "memory": self.task_config.memory,
78
+ "accelerators": self.task_config.accelerators,
79
+ "accelerator_type": self.task_config.accelerator_type,
80
+ "country_code": _validate_and_format_country_code(self.task_config.country_code),
81
+ "provider": self.task_config.provider,
82
+ }
83
+ config = {k: v for k, v in config.items() if v is not None}
84
+ s = Struct()
85
+ s.update(config)
86
+ return json_format.MessageToDict(s)
87
+
88
+
89
+ def _validate_and_format_country_code(country_code: Optional[str]) -> Optional[str]:
90
+ if not country_code:
91
+ return None
92
+ if len(country_code) != 2:
93
+ raise FlyteUserException("Invalid country code. Please provide a valid two-letter country code. (e.g. DE)")
94
+ return country_code.upper()
95
+
96
+
97
+ # Inject the Perian plugin into flytekits dynamic plugin loading system
98
+ TaskPlugins.register_pythontask_plugin(PerianConfig, PerianTask)
@@ -0,0 +1,92 @@
1
+ Metadata-Version: 2.1
2
+ Name: flytekitplugins-perian-job
3
+ Version: 1.12.0
4
+ Summary: Flyte agent for Perian Job Platform (perian.io)
5
+ Author: Omar Tarabai
6
+ Author-email: otarabai@perian.io
7
+ License: apache2
8
+ Classifier: Intended Audience :: Science/Research
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: Apache Software License
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Topic :: Scientific/Engineering
16
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
17
+ Classifier: Topic :: Software Development
18
+ Classifier: Topic :: Software Development :: Libraries
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: >=3.8
21
+ Description-Content-Type: text/markdown
22
+
23
+ # Flytekit Perian Job Platform Plugin
24
+
25
+ Flyte Agent plugin for executing Flyte tasks on Perian Job Platform (perian.io).
26
+
27
+ Perian Job Platform is still in closed beta. Contact support@perian.io if you are interested in trying it out.
28
+
29
+ To install the plugin, run the following command:
30
+
31
+ ```bash
32
+ pip install flytekitplugins-perian-job
33
+ ```
34
+
35
+ ## Getting Started
36
+
37
+ This plugin allows executing `PythonFunctionTask` on Perian.
38
+
39
+ An [ImageSpec](https://docs.flyte.org/en/latest/user_guide/customizing_dependencies/imagespec.html) need to be built with the perian agent plugin installed.
40
+
41
+ ### Parameters
42
+
43
+ The following parameters can be used to set the requirements for the Perian task. If any of the requirements are skipped, it is replaced with the cheapest option. At least one requirement value should be set.
44
+ * `cores`: Number of CPU cores
45
+ * `memory`: Amount of memory in GB
46
+ * `accelerators`: Number of accelerators
47
+ * `accelerator_type`: Type of accelerator (e.g. 'A100'). For a full list of supported accelerators, use the perian CLI list-accelerators command.
48
+ * `country_code`: Country code to run the job in (e.g. 'DE')
49
+
50
+ ### Credentials
51
+
52
+ The following [secrets](https://docs.flyte.org/en/latest/user_guide/productionizing/secrets.html) are required to be defined for the agent server:
53
+ * Perian credentials:
54
+ * `perian_organization`
55
+ * `perian_token`
56
+ * AWS credentials for accessing the Flyte storage bucket. You might need to create long-lived credentials to avoid expiry when running tasks. These credentials are never logged by Perian and are stored only until it is used, then immediately deleted:
57
+ * `aws_access_key_id`
58
+ * `aws_secret_access_key`
59
+ * (Optional) Custom docker registry for pulling the Flyte image:
60
+ * `docker_registry_url`
61
+ * `docker_registry_username`
62
+ * `docker_registry_password`
63
+
64
+ ### Example
65
+
66
+ `example.py` workflow example:
67
+ ```python
68
+ from flytekit import ImageSpec, task, workflow
69
+ from flytekitplugins.perian_job import PerianConfig
70
+
71
+ image_spec = ImageSpec(
72
+ name="flyte-test",
73
+ registry="my-registry",
74
+ python_version="3.11",
75
+ apt_packages=["wget", "curl", "git"],
76
+ packages=[
77
+ "flytekitplugins-perian-job",
78
+ ],
79
+ )
80
+
81
+ @task(container_image=image_spec,
82
+ task_config=PerianConfig(
83
+ accelerators=1,
84
+ accelerator_type="A100",
85
+ ))
86
+ def perian_hello(name: str) -> str:
87
+ return f"hello {name}!"
88
+
89
+ @workflow
90
+ def my_wf(name: str = "world") -> str:
91
+ return perian_hello(name=name)
92
+ ```
@@ -0,0 +1,14 @@
1
+ README.md
2
+ setup.py
3
+ flytekitplugins/perian_job/__init__.py
4
+ flytekitplugins/perian_job/agent.py
5
+ flytekitplugins/perian_job/task.py
6
+ flytekitplugins_perian_job.egg-info/PKG-INFO
7
+ flytekitplugins_perian_job.egg-info/SOURCES.txt
8
+ flytekitplugins_perian_job.egg-info/dependency_links.txt
9
+ flytekitplugins_perian_job.egg-info/entry_points.txt
10
+ flytekitplugins_perian_job.egg-info/namespace_packages.txt
11
+ flytekitplugins_perian_job.egg-info/requires.txt
12
+ flytekitplugins_perian_job.egg-info/top_level.txt
13
+ tests/__init__.py
14
+ tests/test_perian.py
@@ -0,0 +1,2 @@
1
+ [flytekit.plugins]
2
+ perian_job = flytekitplugins.perian_job
@@ -0,0 +1,2 @@
1
+ flytekit<2.0.0,>=1.12.0
2
+ perian>=0.2.3
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,39 @@
1
+ from setuptools import setup
2
+
3
+ PLUGIN_NAME = "perian_job"
4
+
5
+ microlib_name = f"flytekitplugins-{PLUGIN_NAME}"
6
+
7
+ plugin_requires = ["flytekit>=1.12.0,<2.0.0", "perian>=0.2.3"]
8
+
9
+ __version__ = "1.12.0"
10
+
11
+ setup(
12
+ name=microlib_name,
13
+ version=__version__,
14
+ author="Omar Tarabai",
15
+ author_email="otarabai@perian.io",
16
+ description="Flyte agent for Perian Job Platform (perian.io)",
17
+ long_description=open("README.md").read(),
18
+ long_description_content_type="text/markdown",
19
+ namespace_packages=["flytekitplugins"],
20
+ packages=[f"flytekitplugins.{PLUGIN_NAME}"],
21
+ install_requires=plugin_requires,
22
+ license="apache2",
23
+ python_requires=">=3.8",
24
+ classifiers=[
25
+ "Intended Audience :: Science/Research",
26
+ "Intended Audience :: Developers",
27
+ "License :: OSI Approved :: Apache Software License",
28
+ "Programming Language :: Python :: 3.8",
29
+ "Programming Language :: Python :: 3.9",
30
+ "Programming Language :: Python :: 3.10",
31
+ "Programming Language :: Python :: 3.11",
32
+ "Topic :: Scientific/Engineering",
33
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
34
+ "Topic :: Software Development",
35
+ "Topic :: Software Development :: Libraries",
36
+ "Topic :: Software Development :: Libraries :: Python Modules",
37
+ ],
38
+ entry_points={"flytekit.plugins": [f"{PLUGIN_NAME}=flytekitplugins.{PLUGIN_NAME}"]},
39
+ )
File without changes
@@ -0,0 +1,43 @@
1
+ from collections import OrderedDict
2
+
3
+ from flytekitplugins.perian_job import PerianConfig, PerianTask
4
+
5
+ from flytekit import task
6
+ from flytekit.configuration import DefaultImages, ImageConfig, SerializationSettings
7
+ from flytekit.extend import get_serializable
8
+
9
+
10
+ def test_perian_task():
11
+ task_config = PerianConfig(
12
+ cores=2,
13
+ memory="8",
14
+ accelerators=1,
15
+ accelerator_type="A100",
16
+ country_code="DE",
17
+ )
18
+ container_image = DefaultImages.default_image()
19
+
20
+ @task(
21
+ task_config=task_config,
22
+ container_image=container_image,
23
+ )
24
+ def say_hello(name: str) -> str:
25
+ return f"Hello, {name}."
26
+
27
+ assert say_hello.task_config == task_config
28
+ assert say_hello.task_type == "perian_task"
29
+ assert isinstance(say_hello, PerianTask)
30
+
31
+ serialization_settings = SerializationSettings(image_config=ImageConfig())
32
+ task_spec = get_serializable(OrderedDict(), serialization_settings, say_hello)
33
+ template = task_spec.template
34
+ container = template.container
35
+
36
+ assert template.custom == {
37
+ 'accelerator_type': 'A100',
38
+ 'accelerators': 1.0,
39
+ 'cores': 2.0,
40
+ 'country_code': 'DE',
41
+ 'memory': '8',
42
+ }
43
+ assert container.image == container_image