@@ -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 |