diff --git a/README.md b/README.md new file mode 100644 index 0000000..318a972 --- /dev/null +++ b/README.md @@ -0,0 +1,102 @@ +script-manager +============== + + +[![Build Status](https://scrutinizer-ci.com/g/yetone/script-manager/badges/build.png?b=master)](https://scrutinizer-ci.com/g/yetone/script-manager/build-status/master) + + +A command-line interface. Just a simple and crude implementation of Flask-Script. + + +# Examples + +If you create a `test.py` file like this: + +```python +from script_manager import Manager + +manager = Manager('I am a command') + + +@manager.command +def run(host='127.0.0.1', port=8080, hehe=1): + print('Running at http://{}:{}'.format(host, port)) + + +@manager.command +def test(name, age): + """Just print my information + + :param name: This is my name + :param age: This is my age + """ + print('My name is {}, and I have {} years old.'.format(name, age)) + + +if __name__ == '__main__': + manager.run() +``` + +Then you can run command in shell: + +```shell +➜ python test.py -h +usage: test.py [-h] run test + +I am a command + +positional arguments: + run + test Just print my information + +optional arguments: + -h, --help show this help message and exit + +``` + +and: + +```shell +➜ python test.py run -h +usage: test.py [-h] [-H HOST] [-p PORT] [--hehe HEHE] + +optional arguments: + -h, --help show this help message and exit + -H HOST, --host HOST + -p PORT, --port PORT + --hehe HEHE + +``` + +and: + +```shell +➜ python test.py test -h +usage: test.py [-h] name age + +Just print my information + +positional arguments: + name This is my name + age This is my age + +optional arguments: + -h, --help show this help message and exit + +``` + +and: + +```shell +➜ python test.py run -H 0.0.0.0 -p 8888 +Running at http://0.0.0.0:8888 + +``` + +and: + +```shell +➜ python test.py test yetone 12 +My name is yetone, and I have 12 years old. + +``` diff --git a/README.rst b/README.rst deleted file mode 100644 index fa1ed70..0000000 --- a/README.rst +++ /dev/null @@ -1,7 +0,0 @@ -script-manager -============== - -.. image:: https://travis-ci.org/yetone/script-manager.png?branch=master - :target: https://travis-ci.org/yetone/script-manager - -A command-line interface. Just a simple and crude implementation of Flask-Script. diff --git a/script_manager/command.py b/script_manager/command.py index 17583d1..a51d7cd 100644 --- a/script_manager/command.py +++ b/script_manager/command.py @@ -12,7 +12,9 @@ def __init__(self, func, docstring=None): docstring = parse_docstring(func.__doc__) self.docstring = docstring - self.arg_parser = argparse.ArgumentParser(description=self.docstring and self.docstring.description) + self.arg_parser = argparse.ArgumentParser( + description=self.docstring and self.docstring.description + ) argspec = getargspec(func) args = argspec.args @@ -24,6 +26,9 @@ def __init__(self, func, docstring=None): defaults = defaults or {} for arg in args + list(defaults.keys()): + if arg == 'help': + raise Exception("Your arg can't named as 'help'!") + arg_kwargs = {} if self.docstring and arg in self.docstring.params: @@ -49,9 +54,21 @@ def __init__(self, func, docstring=None): else: arg_kwargs['type'] = type(default) - self.add_argument('-%s' % arg[0], - '--%s' % arg, - **arg_kwargs) + prefix_letter = arg[0] + if prefix_letter == 'h': + prefix_letter = 'H' + + brief_flag = '-%s' % prefix_letter + flag = '--%s' % arg + + string_actions = self.get_string_actions() + + if brief_flag in string_actions: + brief_flag = None + + arg_args = filter(None, (brief_flag, flag)) + + self.add_argument(*arg_args, **arg_kwargs) self.func = func self.__doc__ = func.__doc__ @@ -59,6 +76,9 @@ def __init__(self, func, docstring=None): def add_argument(self, *args, **kwargs): self.arg_parser.add_argument(*args, **kwargs) + def get_string_actions(self): + return self.arg_parser._option_string_actions + def run(self, *args): _args = self.arg_parser.parse_args(args) self.func(**_args.__dict__) diff --git a/tests.py b/tests.py index e9fa453..5104f24 100644 --- a/tests.py +++ b/tests.py @@ -23,6 +23,7 @@ def run(command_line, manager_run): class Test(unittest.TestCase): + @pytest.fixture(autouse=True) def inject_fixtures(self, capsys): self.capsys = capsys @@ -162,3 +163,16 @@ def wow(a, b, c=1): self.assertIn("I'm a", out) self.assertIn("I'm b", out) self.assertIn("I'm c", out) + + def test_conflict_flag(self): + manager = Manager() + + @manager.command + def hello(host='127.0.0.1', boy=1, bird=2): + print('hello') + + run('manage.py hello -h', manager.run) + out, err = self.capsys.readouterr() + self.assertIn('-H HOST, --host HOST', out) + self.assertIn('-b BOY, --boy BOY', out) + self.assertIn('--bird BIRD', out) diff --git a/tox.ini b/tox.ini index 17ab3d9..7b262b3 100644 --- a/tox.ini +++ b/tox.ini @@ -4,5 +4,7 @@ envlist = py{27,36} [testenv] passenv = * -deps = pytest -commands = pytest tests.py \ No newline at end of file +deps = + pytest + pytest-cov +commands = pytest tests.py --cov=script_manager