This is an automated email from the ASF dual-hosted git repository.
caishunfeng pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git
The following commit(s) were added to refs/heads/dev by this push:
new 3025f67 [python] Add mechanism cli only with version as subcommand
(#8516)
3025f67 is described below
commit 3025f67d370e02ebae075a4ef68e1d7f0461b2d6
Author: Jiajie Zhong <[email protected]>
AuthorDate: Thu Feb 24 16:05:55 2022 +0800
[python] Add mechanism cli only with version as subcommand (#8516)
* Add basic cli mechanism with Click, for now just including
one single subcommand `version`
* Add general and easy test class in tests/testing/cli, and
test to version
* Add sphinx-click to general cli docs basic on click
---
.../pydolphinscheduler/README.md | 4 +-
.../docs/source/{index.rst => cli.rst} | 32 ++++----
.../pydolphinscheduler/docs/source/conf.py | 2 +
.../pydolphinscheduler/docs/source/index.rst | 1 +
.../pydolphinscheduler/setup.py | 7 ++
.../src/pydolphinscheduler/cli/__init__.py | 18 +++++
.../src/pydolphinscheduler/cli/commands.py | 48 ++++++++++++
.../pydolphinscheduler/tests/cli/__init__.py | 18 +++++
.../pydolphinscheduler/tests/cli/test_version.py | 59 ++++++++++++++
.../pydolphinscheduler/tests/testing/cli.py | 91 ++++++++++++++++++++++
10 files changed, 259 insertions(+), 21 deletions(-)
diff --git a/dolphinscheduler-python/pydolphinscheduler/README.md
b/dolphinscheduler-python/pydolphinscheduler/README.md
index 9cc524d..32a7ff6 100644
--- a/dolphinscheduler-python/pydolphinscheduler/README.md
+++ b/dolphinscheduler-python/pydolphinscheduler/README.md
@@ -40,8 +40,8 @@ your workflow by python code, aka workflow-as-codes.
# Install
$ pip install apache-dolphinscheduler
-# Check installation, it is success if you see version output, here we use
0.1.0 as example
-$ python -c "import pydolphinscheduler; print(pydolphinscheduler.__version__)"
+# Verify installation is successful, it will show the version of
apache-dolphinscheduler, here we use 0.1.0 as example
+$ pydolphinscheduler version
0.1.0
```
diff --git a/dolphinscheduler-python/pydolphinscheduler/docs/source/index.rst
b/dolphinscheduler-python/pydolphinscheduler/docs/source/cli.rst
similarity index 58%
copy from dolphinscheduler-python/pydolphinscheduler/docs/source/index.rst
copy to dolphinscheduler-python/pydolphinscheduler/docs/source/cli.rst
index b04c26f..60e8231 100644
--- a/dolphinscheduler-python/pydolphinscheduler/docs/source/index.rst
+++ b/dolphinscheduler-python/pydolphinscheduler/docs/source/cli.rst
@@ -15,28 +15,22 @@
specific language governing permissions and limitations
under the License.
-PyDolphinScheduler
-==================
+Command Line Interface
+======================
-**PyDolphinScheduler** is Python API for `Apache DolphinScheduler
<https://dolphinscheduler.apache.org>`_,
-which allow you definition your workflow by Python code, aka workflow-as-codes.
+*PyDolphinScheduler* have mechanism call CLI(command line interface) to help
user control it in Shell.
-I could go and find how to :ref:`install <start:getting started>` the project.
Or if you want to see simply example
-then go and see :doc:`tutorial` for more detail.
+Prepare
+-------
+You have to :ref:`install PyDolphinScheduler <start:installing
pydolphinscheduler>` first before you using
+its CLI
-.. toctree::
- :maxdepth: 2
+Usage
+-----
- start
- tutorial
- concept
- tasks/index
- api
+Here is basic usage about the command line of *PyDolphinScheduler*
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
+.. click:: pydolphinscheduler.cli.commands:cli
+ :prog: pydolphinscheduler
+ :nested: full
diff --git a/dolphinscheduler-python/pydolphinscheduler/docs/source/conf.py
b/dolphinscheduler-python/pydolphinscheduler/docs/source/conf.py
index 5ee73a5..e22b3bb 100644
--- a/dolphinscheduler-python/pydolphinscheduler/docs/source/conf.py
+++ b/dolphinscheduler-python/pydolphinscheduler/docs/source/conf.py
@@ -55,6 +55,8 @@ extensions = [
"sphinx.ext.viewcode",
"sphinx.ext.autosectionlabel",
"sphinx_rtd_theme",
+ # Documenting command line interface
+ "sphinx_click.ext",
]
# Add any paths that contain templates here, relative to this directory.
diff --git a/dolphinscheduler-python/pydolphinscheduler/docs/source/index.rst
b/dolphinscheduler-python/pydolphinscheduler/docs/source/index.rst
index b04c26f..ad4c93d 100644
--- a/dolphinscheduler-python/pydolphinscheduler/docs/source/index.rst
+++ b/dolphinscheduler-python/pydolphinscheduler/docs/source/index.rst
@@ -32,6 +32,7 @@ then go and see :doc:`tutorial` for more detail.
tutorial
concept
tasks/index
+ cli
api
Indices and tables
diff --git a/dolphinscheduler-python/pydolphinscheduler/setup.py
b/dolphinscheduler-python/pydolphinscheduler/setup.py
index cd6eb3e..117ffee 100644
--- a/dolphinscheduler-python/pydolphinscheduler/setup.py
+++ b/dolphinscheduler-python/pydolphinscheduler/setup.py
@@ -31,12 +31,14 @@ version = "0.1.0"
# Start package required
prod = [
+ "click>=8.0.0",
"py4j~=0.10",
]
doc = [
"sphinx>=4.3",
"sphinx_rtd_theme>=1.0",
+ "sphinx-click>=3.0",
]
test = [
@@ -125,4 +127,9 @@ setup(
"test": test,
"doc": doc,
},
+ entry_points={
+ "console_scripts": [
+ "pydolphinscheduler = pydolphinscheduler.cli.commands:cli",
+ ],
+ },
)
diff --git
a/dolphinscheduler-python/pydolphinscheduler/src/pydolphinscheduler/cli/__init__.py
b/dolphinscheduler-python/pydolphinscheduler/src/pydolphinscheduler/cli/__init__.py
new file mode 100644
index 0000000..5f30c83
--- /dev/null
+++
b/dolphinscheduler-python/pydolphinscheduler/src/pydolphinscheduler/cli/__init__.py
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+"""Commands line interface of pydolphinscheduler."""
diff --git
a/dolphinscheduler-python/pydolphinscheduler/src/pydolphinscheduler/cli/commands.py
b/dolphinscheduler-python/pydolphinscheduler/src/pydolphinscheduler/cli/commands.py
new file mode 100644
index 0000000..a430f45
--- /dev/null
+++
b/dolphinscheduler-python/pydolphinscheduler/src/pydolphinscheduler/cli/commands.py
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+"""Commands line interface's command of pydolphinscheduler."""
+
+import click
+from click import echo
+
+from pydolphinscheduler import __version__
+
+version_option_val = ["major", "minor", "micro"]
+
+
[email protected]()
+def cli():
+ """Apache DolphinScheduler Python API's command line interface."""
+
+
[email protected]()
[email protected](
+ "--part",
+ "-p",
+ required=False,
+ type=click.Choice(version_option_val, case_sensitive=False),
+ multiple=False,
+ help="The part of version your want to get.",
+)
+def version(part: str) -> None:
+ """Show current version of pydolphinscheduler."""
+ if part:
+ idx = version_option_val.index(part)
+ echo(f"{__version__.split('.')[idx]}")
+ else:
+ echo(f"{__version__}")
diff --git a/dolphinscheduler-python/pydolphinscheduler/tests/cli/__init__.py
b/dolphinscheduler-python/pydolphinscheduler/tests/cli/__init__.py
new file mode 100644
index 0000000..f1a4396
--- /dev/null
+++ b/dolphinscheduler-python/pydolphinscheduler/tests/cli/__init__.py
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+"""Init command line interface tests."""
diff --git
a/dolphinscheduler-python/pydolphinscheduler/tests/cli/test_version.py
b/dolphinscheduler-python/pydolphinscheduler/tests/cli/test_version.py
new file mode 100644
index 0000000..df17759
--- /dev/null
+++ b/dolphinscheduler-python/pydolphinscheduler/tests/cli/test_version.py
@@ -0,0 +1,59 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+"""Test command line interface subcommand version."""
+
+import pytest
+
+from pydolphinscheduler import __version__
+from pydolphinscheduler.cli.commands import cli
+from tests.testing.cli import CliTestWrapper
+
+
+def test_version():
+ """Test whether subcommand `version` correct."""
+ cli_test = CliTestWrapper(cli, ["version"])
+ cli_test.assert_success(output=f"{__version__}")
+
+
[email protected](
+ "part, idx",
+ [
+ ("major", 0),
+ ("minor", 1),
+ ("micro", 2),
+ ],
+)
+def test_version_part(part: str, idx: int):
+ """Test subcommand `version` option `--part`."""
+ cli_test = CliTestWrapper(cli, ["version", "--part", part])
+ cli_test.assert_success(output=f"{__version__.split('.')[idx]}")
+
+
[email protected](
+ "option, output",
+ [
+ # not support option
+ (["version", "--not-support"], "No such option"),
+ # not support option value
+ (["version", "--part", "abc"], "Invalid value for '--part'"),
+ ],
+)
+def test_version_not_support_option(option, output):
+ """Test subcommand `version` not support option or option value."""
+ cli_test = CliTestWrapper(cli, option)
+ cli_test.assert_fail(ret_code=2, output=output, fuzzy=True)
diff --git a/dolphinscheduler-python/pydolphinscheduler/tests/testing/cli.py
b/dolphinscheduler-python/pydolphinscheduler/tests/testing/cli.py
new file mode 100644
index 0000000..1585920
--- /dev/null
+++ b/dolphinscheduler-python/pydolphinscheduler/tests/testing/cli.py
@@ -0,0 +1,91 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+"""Utils of command line test."""
+
+
+import os
+
+from click.testing import CliRunner
+
+
+class CliTestWrapper:
+ """Wrap command click CliRunner.invoke."""
+
+ _dev_mode_env_name = "PY_DOLPHINSCHEDULER_DEV_MODE"
+ _dev_mode_true_val = {"true", "t", "1"}
+
+ def __init__(self, *args, **kwargs):
+ runner = CliRunner()
+ self.result = runner.invoke(*args, **kwargs)
+ self.show_result_output()
+
+ def _assert_output(self, output: str = None, fuzzy: bool = False):
+ """Assert between `CliRunner.invoke.result.output` and parameter
`output`.
+
+ :param output: The output will check compare to the
``CliRunner.invoke.output``.
+ :param fuzzy: A flag define whether assert :param:`output` in fuzzy or
not.
+ Check if `CliRunner.invoke.output` contain :param:`output` is set
``True``
+ and CliRunner.invoke.output equal to :param:`output` if we set it
``False``.
+ """
+ if not output:
+ return
+ if fuzzy:
+ assert output in self.result.output
+ else:
+ assert self.result.output.rstrip("\n") == output
+
+ def show_result_output(self):
+ """Print `CliRunner.invoke.result` output content in debug mode.
+
+ It read variable named `PY_DOLPHINSCHEDULER_DEV_MODE` from env, when
it set to `true` or `t` or `1`
+ will print result output when class :class:`CliTestWrapper` is
initialization.
+ """
+ dev_mode = str(os.getenv(self._dev_mode_env_name))
+ if dev_mode.strip().lower() in self._dev_mode_true_val:
+ print(f"\n{self.result.output}\n")
+
+ def assert_success(self, output: str = None, fuzzy: bool = False):
+ """Assert test is success.
+
+ It would check whether `CliRunner.invoke.exit_code` equals to `0`,
with no
+ exception at the same time. It's also can test the content of
`CliRunner.invoke.output`.
+
+ :param output: The output will check compare to the
``CliRunner.invoke.output``.
+ :param fuzzy: A flag define whether assert :param:`output` in fuzzy or
not.
+ Check if `CliRunner.invoke.output` contain :param:`output` is set
``True``
+ and CliRunner.invoke.output equal to :param:`output` if we set it
``False``.
+ """
+ assert self.result.exit_code == 0
+ if self.result.exception:
+ raise self.result.exception
+ self._assert_output(output, fuzzy)
+
+ def assert_fail(self, ret_code: int, output: str = None, fuzzy: bool =
False):
+ """Assert test is fail.
+
+ It would check whether `CliRunner.invoke.exit_code` equals to
:param:`ret_code`,
+ and it will also can test the content of `CliRunner.invoke.output`.
+
+ :param ret_code: The returning code of this fail test.
+ :param output: The output will check compare to the
``CliRunner.invoke.output``.
+ :param fuzzy: A flag define whether assert :param:`output` in fuzzy or
not.
+ Check if `CliRunner.invoke.output` contain :param:`output` is set
``True``
+ and CliRunner.invoke.output equal to :param:`output` if we set it
``False``.
+ """
+ assert ret_code == self.result.exit_code
+ self._assert_output(output, fuzzy)