diff --git a/README.md b/README.md index becccd8..0f015c0 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,12 @@ Tutorials to get started with generic pipelines in Elyra: - [Run generic pipelines on Apache Airflow](pipelines/run-generic-pipelines-on-apache-airflow) - [Run runtime-specific pipelines on Kubeflow Pipelines](pipelines/run-pipelines-on-kubeflow-pipelines) +### Pipeline component catalog connectors + +Elyra loads [custom components](https://elyra.readthedocs.io/en/stable/user_guide/pipeline-components.html) from component catalogs: +- [Find catalog connectors](component-catalog-connectors/connector-directory.md) +- [Build a custom catalog connector](component-catalog-connectors/build-a-custom-connector.md) + ### Custom pipeline component examples Pipeline nodes are implemented using diff --git a/component-catalog-connectors/README.md b/component-catalog-connectors/README.md new file mode 100644 index 0000000..b52ea15 --- /dev/null +++ b/component-catalog-connectors/README.md @@ -0,0 +1,3 @@ +## Component catalog connectors + +This content is under development. diff --git a/component-catalog-connectors/build-a-custom-connector.md b/component-catalog-connectors/build-a-custom-connector.md new file mode 100644 index 0000000..e816b62 --- /dev/null +++ b/component-catalog-connectors/build-a-custom-connector.md @@ -0,0 +1,3 @@ +## How to build a component catalog connector + +This content is under development. \ No newline at end of file diff --git a/component-catalog-connectors/connector-directory.md b/component-catalog-connectors/connector-directory.md new file mode 100644 index 0000000..2a3e389 --- /dev/null +++ b/component-catalog-connectors/connector-directory.md @@ -0,0 +1,11 @@ +## Component catalog connectors + +The following third-party catalog connectors should work with Elyra. Connectors are provided as is and, unless specified otherwise, are not maintained by the Elyra core committers. + +- To add your connector to the list [create a pull request](https://github.com/elyra-ai/examples/pulls). +- Learn [how to build your own catalog connector](build-a-custom-connector.md). + +| Connector | Description | +| ----------- | ----------- | +| [Machine Learning Exchange](mlx-connector/) | Provides access to [Machine Learning Exchange](https://github.com/machine-learning-exchange) catalogs | + diff --git a/component-catalog-connectors/mlx-connector/MANIFEST.in b/component-catalog-connectors/mlx-connector/MANIFEST.in new file mode 100644 index 0000000..4bd1206 --- /dev/null +++ b/component-catalog-connectors/mlx-connector/MANIFEST.in @@ -0,0 +1,37 @@ +# +# Copyright 2018-2021 Elyra Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# exclude from ANY directory +global-exclude *.ipynb +global-exclude *.py[cod] +global-exclude __pycache__ +global-exclude .git +global-exclude .ipynb_checkpoints +global-exclude .DS_Store +global-exclude *.sh +global-exclude docs +global-exclude tests + +# explicit includes +include CONTRIBUTING.md +include README.md +include LICENSE +include dist/*.tgz + +recursive-exclude * __pycache__ +recursive-exclude * *.py[co] + +recursive-include mlx_catalog_connector mlx-catalog.json diff --git a/component-catalog-connectors/mlx-connector/Makefile b/component-catalog-connectors/mlx-connector/Makefile new file mode 100644 index 0000000..00bdac2 --- /dev/null +++ b/component-catalog-connectors/mlx-connector/Makefile @@ -0,0 +1,44 @@ +# +# Copyright 2021-2021 Elyra Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +.PHONY: help clean lint test-dependencies source-install install dist + +SHELL:=/bin/bash + +help: +# http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html + @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +clean: + rm -rf dist/ + rm -rf build/ + rm -rf *.egg-info + - pip uninstall -y mlx-component-catalog-connector + +test-dependencies: + @pip install -q -r test_requirements.txt + +lint: test-dependencies + flake8 mlx_catalog_connector + +dist: clean lint ## Build distribution + python setup.py bdist_wheel sdist + +source-install: dist ## Install MLX component connector package from source + pip install . + +install: ## Install MLX component connector package from PyPI + pip install mlx-component-catalog-connector diff --git a/component-catalog-connectors/mlx-connector/README.md b/component-catalog-connectors/mlx-connector/README.md new file mode 100644 index 0000000..04b0d3c --- /dev/null +++ b/component-catalog-connectors/mlx-connector/README.md @@ -0,0 +1,62 @@ +## Machine Learning Exchange catalog connector + +This catalog connector enables Elyra to load Kubeflow Pipelines components from [Machine Learning Exchange](https://github.com/machine-learning-exchange) (MLX) deployments. + +### Install the connector + +You can install the MLX catalog connector from PyPI or source code. Note that a **rebuild of JupyterLab is not required**. + +**Prerequisites** + +- [Install Elyra](https://elyra.readthedocs.io/en/stable/getting_started/installation.html) (version 3.3 and above). +- [Machine Learning Exchange deployment](https://github.com/machine-learning-exchange/mlx) ([quickstart guide](https://github.com/machine-learning-exchange/mlx/tree/main/quickstart)) + +**Install from PyPI** + + ``` + $ pip install mlx-component-catalog-connector + ``` + +**Install from source code** + + ``` + $ git clone https://github.com/elyra-ai/examples.git + $ cd examples/component-catalog-connectors/mlx-connector/ + $ make source-install + ``` + +### Use the connector + +1. Launch JupyterLab. +1. [Open the '`Manage Components`' panel]( +https://elyra.readthedocs.io/en/stable/user_guide/pipeline-components.html#managing-custom-components-using-the-jupyterlab-ui). +1. Add a new MLX component catalog ('`+`' > '`New Machine Learning Exchange Component Catalog`'). +1. Specify a catalog name, e.g. '`MLX dev catalog`'. +1. Select Kubeflow Pipelines as runtime. +1. (Optional) Specify a category under which the catalog's component will be organized in the palette. +1. Configure the `MLX API URL`, e.g. '`http://my-mlx-server.mydomain:8080/`'. + > Note: The Machine Learning Exchange API URL is different from the GUI URL! +1. Apply an optional filter expression to the component names. The `*` (zero or more characters) and `?` (zero or one character) wildcards are supported. +1. Save the catalog entry. +1. Open the Kubeflow Pipelines Visual Pipeline Editor and expand the palette. The components that were loaded from the specified MLX URL are displayed. + +### Uninstall the connector + +1. Remove all MLX catalog entries from the '`Manage Components`' panel. +1. Stop JupyterLab. +1. Uninstall the `mlx-component-catalog-connector` package. + ``` + $ pip uninstall -y mlx-component-catalog-connector + ``` + +### Troubleshooting + +**Problem: The palette does not display any components from the configured catalog.** + +**Solution:** If the the Elyra GUI does not display any error message indicating that a problem was encountered, inspect the JupyterLab log file. + +Example error message (The specified MLX URL is invalid): + +``` +Error fetching component list from MLX catalog http://localhost:8080: ... Failed to establish a new connection: [Errno 61] Connection refused' +``` diff --git a/component-catalog-connectors/mlx-connector/mlx_catalog_connector/__init__.py b/component-catalog-connectors/mlx-connector/mlx_catalog_connector/__init__.py new file mode 100644 index 0000000..febc0a2 --- /dev/null +++ b/component-catalog-connectors/mlx-connector/mlx_catalog_connector/__init__.py @@ -0,0 +1,15 @@ +# +# Copyright 2018-2021 Elyra Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/component-catalog-connectors/mlx-connector/mlx_catalog_connector/_version.py b/component-catalog-connectors/mlx-connector/mlx_catalog_connector/_version.py new file mode 100644 index 0000000..4abcc16 --- /dev/null +++ b/component-catalog-connectors/mlx-connector/mlx_catalog_connector/_version.py @@ -0,0 +1,16 @@ +# +# Copyright 2018-2021 Elyra Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +__version__ = '0.0.1' diff --git a/component-catalog-connectors/mlx-connector/mlx_catalog_connector/mlx-catalog.json b/component-catalog-connectors/mlx-connector/mlx_catalog_connector/mlx-catalog.json new file mode 100644 index 0000000..c8128d0 --- /dev/null +++ b/component-catalog-connectors/mlx-connector/mlx_catalog_connector/mlx-catalog.json @@ -0,0 +1,89 @@ +{ + "$schema": "https://raw.githubusercontent.com/elyra-ai/elyra/master/elyra/metadata/schemas/meta-schema.json", + "$id": "https://raw.githubusercontent.com/elyra-ai/examples/master/component-catalog-connectors/mlx-connector/mlx_catalog_connector/mlx-catalog.json", + "title": "Machine Learning Exchange Component Catalog", + "name": "mlx-catalog", + "display_name": "Machine Learning Exchange Component Catalog", + "schemaspace": "component-registries", + "schemaspace_id": "ae79159a-489d-4656-83a6-1adfbc567c70", + "metadata_class_name": "elyra.pipeline.component_metadata.ComponentCatalogMetadata", + "uihints": { + "title": "Machine Learning Exchange Component Catalog", + "icon": "", + "reference_url": "https://github.com/elyra-ai/examples/tree/master/component-catalog-connectors/mlx-connector" + }, + "properties": { + "schema_name": { + "title": "Schema Name", + "description": "The schema associated with this instance", + "type": "string", + "const": "mlx-catalog" + }, + "display_name": { + "title": "Display Name", + "description": "Display name of this Component Catalog", + "type": "string", + "minLength": 1 + }, + "version": { + "title": "Version", + "description": "The version associated with this instance", + "type": "integer", + "const": 1 + }, + "metadata": { + "description": "Additional data specific to this metadata", + "type": "object", + "properties": { + "description": { + "title": "Description", + "description": "Description of this Component Catalog", + "type": "string", + "default": "Kubeflow Pipelines component catalog" + }, + "runtime": { + "title": "Runtime", + "description": "The Machine Learning Exchange only supports Kubeflow Pipeline components.", + "type": "string", + "enum": ["kfp"], + "default": "kfp", + "uihints": { + "field_type": "dropdown" + } + }, + "categories": { + "title": "Category Names", + "description": "Assign the components in the catalog to one or more categories, to group them in the visual pipeline editor palette.", + "type": "array", + "items": { + "type": "string", + "maxLength": 18 + }, + "uihints": { + "field_type": "array", + "category": "Component Categories" + } + }, + "mlx_api_url": { + "title": "MLX API URL", + "description": "API endpoint URL for the Machine Learning Exchange server", + "type": "string", + "format": "uri", + "uihints": { + "category": "Source" + } + }, + "filter": { + "title": "Component name filter", + "description": "Only return components that match the specified name filter expression. * and ? are valid wildcards.", + "type": "string", + "uihints": { + "category": "Source" + } + } + }, + "required": ["runtime", "mlx_api_url"] + } + }, + "required": ["schema_name", "display_name", "version", "metadata"] +} diff --git a/component-catalog-connectors/mlx-connector/mlx_catalog_connector/mlx_component_catalog_connector.py b/component-catalog-connectors/mlx-connector/mlx_catalog_connector/mlx_component_catalog_connector.py new file mode 100644 index 0000000..145bbc9 --- /dev/null +++ b/component-catalog-connectors/mlx-connector/mlx_catalog_connector/mlx_component_catalog_connector.py @@ -0,0 +1,182 @@ +# +# Copyright 2018-2021 Elyra Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +from http import HTTPStatus +from io import BytesIO +import re +import tarfile +from tempfile import TemporaryFile +from typing import Any +from typing import Dict +from typing import List +from typing import Optional +from urllib.parse import urlparse + +from elyra.pipeline.catalog_connector import ComponentCatalogConnector +import requests + + +class MLXComponentCatalogConnector(ComponentCatalogConnector): + """ + Read component definitions from a Machine Learning Exchange catalog + https://github.com/machine-learning-exchange + """ + + def get_catalog_entries(self, catalog_metadata: Dict[str, Any]) -> List[Dict[str, Any]]: + + """ + Returns a list of component_metadata instances, one per component found in the given registry. + The form that component_metadata takes is determined by requirements of the reader class. + + :param registry_metadata: the dictionary-form of the Metadata instance for a single registry + """ + component_list = [] + + # verify that the required inputs were provided + mlx_api_url = catalog_metadata.get('mlx_api_url') + + if mlx_api_url is None: + self.log.error('Cannot connect to MLX catalog: An API endpoint URL must be provided.') + # return empty component list + return component_list + + if catalog_metadata.get('runtime') != 'kfp': + self.log.error(f'MLX catalog {mlx_api_url} only supports Kubeflow Pipelines.') + # return empty component list + return component_list + + try: + # invoke endpoint to retrieve component list from the catalog + self.log.debug(f'Retrieving component list from MLX catalog \'{mlx_api_url}\'.') + u = urlparse(mlx_api_url) + # assemble MLX component list endpoint URL + endpoint = u._replace(path='/apis/v1alpha1/components').geturl() + + # Query MLX catalog components endpoint + res = requests.get(endpoint) + if res.status_code != HTTPStatus.OK: + self.log.warning(f'Error fetching component list from MLX catalog {mlx_api_url}: ' + f'Request: {endpoint} HTTP code: {res.status_code}.') + return component_list + + if res.headers['Content-Type'] != 'application/json': + self.log.warning(f'Error fetching component list from MLX catalog {mlx_api_url}: ' + f'Unexpected content type: {res.headers["Content-Type"]}.' + f'Content: {res.content}') + return component_list + + # the response is JSON formatted: + # "components": [ + # { + # "id": "component-id-used-for-retrieval", + # "name": "user friendly component name" + # ... + # } + # ] + + # create component filter regex if a filter condition was + # specified by the user + filter_expression = catalog_metadata.get('filter', '').strip() + regex = None + if len(filter_expression) > 0: + regex = filter_expression.replace('*', '.*').replace('?', '.?') + + # post-process the component list by applying the filter regex, if + # one was specified + for component in res.json().get('components', []): + if regex: + if re.fullmatch(regex, component.get('name', ''), flags=re.IGNORECASE): + component_list.append({'mlx_component_id': component.get('id')}) + else: + component_list.append({'mlx_component_id': component.get('id')}) + + except Exception as ex: + self.log.warning(f'Error fetching component list from MLX catalog {mlx_api_url}: {ex}') + + return component_list + + def read_catalog_entry(self, + catalog_entry_data: Dict[str, Any], + catalog_metadata: Dict[str, Any]) -> Optional[str]: + """ + Fetch the component that is identified by catalog_entry_data from + the MLX catalog. + + :param catalog_entry_data: a dictionary that contains the information needed to read the content + of the component definition + :param catalog_metadata: the metadata associated with the catalog in which this catalog entry is + stored; in addition to catalog_entry_data, catalog_metadata may also be + needed to read the component definition for certain types of catalogs + + :returns: the content of the given catalog entry's definition in string form + """ + + # verify that the required inputs were provided + mlx_api_url = catalog_metadata.get('mlx_api_url') + if mlx_api_url is None: + self.log.error('Cannot connect to MLX catalog: An API endpoint URL must be provided.') + return None + + mlx_component_id = catalog_entry_data['mlx_component_id'] + if mlx_component_id is None: + self.log.error(f'Cannot retrieve component specification from MLX catalog {mlx_api_url}: ' + 'A component id must be provided.') + return None + + try: + u = urlparse(mlx_api_url) + # assemble MLX component list endpoint URL + endpoint = u._replace(path=f'apis/v1alpha1/components/{mlx_component_id}/download').geturl() + res = requests.get(endpoint) + except Exception as e: + self.log.error(f'Failed to download component specification {mlx_component_id} ' + f'from {mlx_api_url}: {str(e)}') + return None + + if res.status_code != HTTPStatus.OK: + self.log.error(f'Error fetching component specification {mlx_component_id} ' + f'from MLX catalog {mlx_api_url}: ' + f'Request: {endpoint} HTTP code: {res.status_code}.') + return None + + # response type should be 'application/gzip' + # Content-Disposition: attachment; filename=model-fairness-check.tgz + with TemporaryFile() as fp: + fp.write(res.content) + fp.seek(0) + try: + tar = tarfile.open(fileobj=BytesIO(fp.read()), + mode='r:gz') + if len(tar.getnames()) > 1: + self.log.error(f'The response archive contains more than one member: {tar.getnames()}') + + return tar.extractfile(tar.getnames()[0]).read() + except Exception as ex: + # the response is not a tgz file + self.log.error(f'The MLX catalog response could not be processed: {ex}') + + return None + + def get_hash_keys(self) -> List[Any]: + """ + Identifies the unique MLX catalog key that read_catalog_entry can use + to fetch an entry from the catalog. Method get_catalog_entries retrieves + the list of available key values. + + :returns: a list of keys, which is for MLX the component id + """ + return ['mlx_component_id'] diff --git a/component-catalog-connectors/mlx-connector/mlx_catalog_connector/mlx_schema_provider.py b/component-catalog-connectors/mlx-connector/mlx_catalog_connector/mlx_schema_provider.py new file mode 100644 index 0000000..043ac34 --- /dev/null +++ b/component-catalog-connectors/mlx-connector/mlx_catalog_connector/mlx_schema_provider.py @@ -0,0 +1,48 @@ +# +# Copyright 2018-2021 Elyra Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import json +import logging +from pathlib import Path +from typing import Dict +from typing import List + +from elyra.metadata.schema import SchemasProvider + + +class MLXSchemasProvider(SchemasProvider): + """ + Enables BYO catalog connector for the Machine Learning Exchange + """ + + def get_schemas(self) -> List[Dict]: + """ + Return the MLX catalog connector schema + """ + # use Elyra logger + log = logging.getLogger('ElyraApp') + mlx_catalog_schema_defs = [] + try: + # load MLX catalog schema definition + mlx_catalog_connector_schema_file = Path(__file__).parent / 'mlx-catalog.json' + log.debug(f'Reading MLX catalog connector schema from {mlx_catalog_connector_schema_file}') + with open(mlx_catalog_connector_schema_file, 'r') as fp: + mlx_catalog_connector_schema = json.load(fp) + mlx_catalog_schema_defs.append(mlx_catalog_connector_schema) + except Exception as ex: + log.error(f'Error reading MLX catalog connector schema {mlx_catalog_connector_schema_file}: {ex}') + + return mlx_catalog_schema_defs diff --git a/component-catalog-connectors/mlx-connector/setup.cfg b/component-catalog-connectors/mlx-connector/setup.cfg new file mode 100644 index 0000000..e35c831 --- /dev/null +++ b/component-catalog-connectors/mlx-connector/setup.cfg @@ -0,0 +1,53 @@ +# +# Copyright 2018-2021 Elyra Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +[bdist_wheel] +universal=0 + +[metadata] +description_file=README.md + +[flake8] +application-import-names = catalog_connector +application-package-names = catalog_connector +enable-extensions = G +# References: +# https://flake8.readthedocs.io/en/latest/user/configuration.html +# https://flake8.readthedocs.io/en/latest/user/error-codes.html +# https://docs.openstack.org/hacking/latest/user/hacking.html +ignore = + # Import formatting + E4, + # Comparing types instead of isinstance + E721, + # Assigning lambda expression + E731, + # Ambiguous variable names + E741, + # File contains nothing but comments + H104, + # Include name with TODOs as in # TODO(yourname) + H101, + # Enable mocking + H216, + # Multi line docstrings should start without a leading new line + H404, + # Multi line docstrings should start with a one line summary followed by an empty line + H405, + # Allow breaks after binary operators + W504 +import-order-style = google +max-line-length = 120 diff --git a/component-catalog-connectors/mlx-connector/setup.py b/component-catalog-connectors/mlx-connector/setup.py new file mode 100644 index 0000000..59646c0 --- /dev/null +++ b/component-catalog-connectors/mlx-connector/setup.py @@ -0,0 +1,71 @@ +# +# Copyright 2018-2021 Elyra Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os + +from setuptools import find_packages, setup + +long_desc = """ + Elyra component catalog connector for the Machine Learning Exchange + """ + +here = os.path.abspath(os.path.dirname(__file__)) + +version_ns = {} +with open(os.path.join(here, 'mlx_catalog_connector', '_version.py')) as f: + exec(f.read(), {}, version_ns) + +setup_args = dict( + name="mlx-component-catalog-connector", + version=version_ns['__version__'], + url="https://github.com/elyra-ai/examples", + description="Elyra component catalog connector for the Machine Learning Exchange", + long_description=long_desc, + author="Elyra Maintainers", + license="Apache License Version 2.0", + packages=find_packages(), + install_requires=[ + 'elyra==3.3.0.dev0', + 'requests' + ], + setup_requires=['flake8'], + include_package_data=True, + entry_points={ + 'metadata.schemas_providers': [ + 'mlx-catalog-schema = mlx_catalog_connector.mlx_schema_provider:MLXSchemasProvider' + ], + 'elyra.component.catalog_types': [ + 'mlx-catalog = mlx_catalog_connector.mlx_component_catalog_connector:MLXComponentCatalogConnector' + ], + }, + classifiers=[ + 'Development Status :: 4 - Beta', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Topic :: Scientific/Engineering', + 'Topic :: Scientific/Engineering :: Artificial Intelligence', + 'Topic :: Software Development', + 'Topic :: Software Development :: Libraries', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + ] +) + + +if __name__ == '__main__': + setup(**setup_args) diff --git a/component-catalog-connectors/mlx-connector/test_requirements.txt b/component-catalog-connectors/mlx-connector/test_requirements.txt new file mode 100644 index 0000000..28f28b5 --- /dev/null +++ b/component-catalog-connectors/mlx-connector/test_requirements.txt @@ -0,0 +1 @@ +flake8>=3.5.0,<3.9.0