| @@ -1,28 +0,0 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| """ | |||||
| The command line interface for hyde. | |||||
| """ | |||||
| import argparse | |||||
| from version import __version__ | |||||
| from engine import init, gen, serve | |||||
| def main(): | |||||
| """ | |||||
| The main function called by hyde executable | |||||
| """ | |||||
| # parser = argparse.ArgumentParser(description='hyde - a python static website generator', | |||||
| # epilog='Use %(prog)s {command} -h to get help on individual commands') | |||||
| # parser.add_argument('-v', '--version', action='version', version='%(prog)s ' + __version__) | |||||
| # parser.add_argument('-s', '--sitepath', action='store', default='.', help="Location of the hyde site") | |||||
| # subcommands = parser.add_subparsers(title="Hyde commands", | |||||
| # description="Entry points for hyde") | |||||
| # init_command = subcommands.add_parser('init', help='Create a new hyde site') | |||||
| # init_command.set_defaults(run=init) | |||||
| # init_command.add_argument('-t', '--template', action='store', default='basic', dest='template', | |||||
| # help='Overwrite the current site if it exists') | |||||
| # init_command.add_argument('-f', '--force', action='store_true', default=False, dest='force', | |||||
| # help='Overwrite the current site if it exists') | |||||
| # args = parser.parse_args() | |||||
| # args.run(args) | |||||
| # | |||||
| @@ -1,113 +0,0 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| """ | |||||
| Declarative interface for argparse | |||||
| """ | |||||
| from argparse import ArgumentParser | |||||
| from collections import namedtuple | |||||
| __all__ = [ | |||||
| 'command', | |||||
| 'subcommand', | |||||
| 'param', | |||||
| 'Application' | |||||
| ] | |||||
| class CommandLine(type): | |||||
| """ | |||||
| Meta class that enables declarative command definitions | |||||
| """ | |||||
| def __new__(mcs, name, bases, attrs): | |||||
| instance = super(CommandLine, mcs).__new__(mcs, name, bases, attrs) | |||||
| subcommands = [] | |||||
| main_command = None | |||||
| for name, member in attrs.iteritems(): | |||||
| if hasattr(member, "command"): | |||||
| main_command = member | |||||
| elif hasattr(member, "subcommand"): | |||||
| subcommands.append(member) | |||||
| main_parser = None | |||||
| def add_arguments(parser, params): | |||||
| """ | |||||
| Adds parameters to the parser | |||||
| """ | |||||
| for parameter in params: | |||||
| parser.add_argument(*parameter.args, **parameter.kwargs) | |||||
| if main_command: | |||||
| main_parser = ArgumentParser(*main_command.command.args, **main_command.command.kwargs) | |||||
| add_arguments(main_parser, main_command.params) | |||||
| subparsers = None | |||||
| if len(subcommands): | |||||
| subparsers = main_parser.add_subparsers() | |||||
| for sub in subcommands: | |||||
| parser = subparsers.add_parser(*sub.subcommand.args, **sub.subcommand.kwargs) | |||||
| parser.set_defaults(run=sub) | |||||
| add_arguments(parser, sub.params) | |||||
| instance.__parser__ = main_parser | |||||
| instance.__main__ = main_command | |||||
| return instance | |||||
| values = namedtuple('__meta_values', 'args, kwargs') | |||||
| class metarator(object): | |||||
| """ | |||||
| A generic decorator that tags the decorated method with | |||||
| the passed in arguments for meta classes to process them. | |||||
| """ | |||||
| def __init__(self, *args, **kwargs): | |||||
| self.values = values._make((args, kwargs)) | |||||
| def metarate(self, func, name='values'): | |||||
| """ | |||||
| Set the values object to the function object's namespace | |||||
| """ | |||||
| setattr(func, name, self.values) | |||||
| return func | |||||
| def __call__(self, func): | |||||
| return self.metarate(func) | |||||
| class command(metarator): | |||||
| """ | |||||
| Used to decorate the main entry point | |||||
| """ | |||||
| def __call__(self, func): | |||||
| return self.metarate(func, name='command') | |||||
| class subcommand(metarator): | |||||
| """ | |||||
| Used to decorate the subcommands | |||||
| """ | |||||
| def __call__(self, func): | |||||
| return self.metarate(func, name='subcommand') | |||||
| class param(metarator): | |||||
| """ | |||||
| Use this decorator instead of `ArgumentParser.add_argument`. | |||||
| """ | |||||
| def __call__(self, func): | |||||
| func.params = func.params if hasattr(func, 'params') else [] | |||||
| func.params.append(self.values) | |||||
| return func | |||||
| class Application(object): | |||||
| """ | |||||
| Barebones base class for command line applications. | |||||
| """ | |||||
| __metaclass__ = CommandLine | |||||
| def parse(self, argv): | |||||
| """ | |||||
| Simple method that delegates to the ArgumentParser | |||||
| """ | |||||
| return self.__parser__.parse_args(argv) | |||||
| def run(self, args): | |||||
| """ | |||||
| Runs the main command or sub command based on user input | |||||
| """ | |||||
| if hasattr(args, 'run'): | |||||
| args.run(self, args) | |||||
| else: | |||||
| self.__main__(args) | |||||
| @@ -1,95 +0,0 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| """ | |||||
| Use nose | |||||
| `$ pip install nose` | |||||
| `$ nosetests` | |||||
| """ | |||||
| from contextlib import nested | |||||
| from hyde.commando import Application, command, subcommand, param | |||||
| from util import trap_exit_pass, trap_exit_fail | |||||
| from mock import Mock, patch | |||||
| try: | |||||
| import cStringIO as StringIO | |||||
| except ImportError: | |||||
| import StringIO | |||||
| import sys | |||||
| class BasicCommandLine(Application): | |||||
| @command(description='test', prog='Basic') | |||||
| @param('--force', action='store_true', dest='force1') | |||||
| @param('--force2', action='store', dest='force2') | |||||
| @param('--version', action='version', version='%(prog)s 1.0') | |||||
| def main(self, params): | |||||
| assert params.force1 == eval(params.force2) | |||||
| self._main() | |||||
| def _main(): pass | |||||
| @trap_exit_fail | |||||
| def test_command_basic(): | |||||
| with patch.object(BasicCommandLine, '_main') as _main: | |||||
| c = BasicCommandLine() | |||||
| args = c.parse(['--force', '--force2', 'True']) | |||||
| c.run(args) | |||||
| assert _main.call_count == 1 | |||||
| args = c.parse(['--force2', 'False']) | |||||
| c.run(args) | |||||
| assert _main.call_count == 2 | |||||
| def test_command_version(): | |||||
| with patch.object(BasicCommandLine, '_main') as _main: | |||||
| c = BasicCommandLine() | |||||
| exception = False | |||||
| try: | |||||
| c.parse(['--version']) | |||||
| assert False | |||||
| except SystemExit: | |||||
| exception = True | |||||
| assert exception | |||||
| assert not _main.called | |||||
| class ComplexCommandLine(Application): | |||||
| @command(description='test', prog='Complex') | |||||
| @param('--force', action='store_true', dest='force1') | |||||
| @param('--force2', action='store', dest='force2') | |||||
| @param('--version', action='version', version='%(prog)s 1.0') | |||||
| def main(self, params): | |||||
| assert params.force1 == eval(params.force2) | |||||
| self._main() | |||||
| @subcommand('sub', description='test') | |||||
| @param('--launch', action='store_true', dest='launch1') | |||||
| @param('--launch2', action='store', dest='launch2') | |||||
| def sub(self, params): | |||||
| assert params.launch1 == eval(params.launch2) | |||||
| self._sub() | |||||
| def _main(): pass | |||||
| def _sub(): pass | |||||
| @trap_exit_pass | |||||
| def test_command_subcommands_usage(): | |||||
| with nested(patch.object(ComplexCommandLine, '_main'), | |||||
| patch.object(ComplexCommandLine, '_sub')) as (_main, _sub): | |||||
| c = ComplexCommandLine() | |||||
| c.parse(['--usage']) | |||||
| @trap_exit_fail | |||||
| def test_command_subcommands(): | |||||
| with nested(patch.object(ComplexCommandLine, '_main'), | |||||
| patch.object(ComplexCommandLine, '_sub')) as (_main, _sub): | |||||
| c = ComplexCommandLine() | |||||
| args = c.parse(['sub', '--launch', '--launch2', 'True']) | |||||
| c.run(args) | |||||
| assert not _main.called | |||||
| assert _sub.call_count == 1 | |||||