Browse Source

Basic Command Line declarative sytnax complete

main
Lakshmi Vyasarajan 14 years ago
parent
commit
4acde4bc64
10 changed files with 244 additions and 286 deletions
  1. +0
    -3
      dev-req.txt
  2. +7
    -4
      hyde/cli.py
  3. +95
    -0
      hyde/command_line.py
  4. +68
    -1
      hyde/engine.py
  5. +15
    -6
      hyde/ext/templates/jinja.py
  6. +10
    -3
      hyde/template.py
  7. +36
    -0
      hyde/tests/test_command_line.py
  8. +1
    -1
      hyde/tests/test_jinja2template.py
  9. +12
    -1
      hyde/tests/util.py
  10. +0
    -267
      pylintrc

+ 0
- 3
dev-req.txt View File

@@ -1,7 +1,4 @@
Django==1.2.3
Genshi==0.6
Jinja2==2.5.5
Mako==0.3.6
Markdown==2.0.3
MarkupSafe==0.11
PyYAML==3.09


+ 7
- 4
hyde/cli.py View File

@@ -3,15 +3,17 @@
The command line interface for hyde.
"""
import argparse

from engine import init, gen, serve
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',
import sys
print sys.argv
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")
@@ -24,4 +26,5 @@ def main():
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)
args.run(args)


+ 95
- 0
hyde/command_line.py View File

@@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
"""
A nice declarative interface for Argument parser
"""
from argparse import ArgumentParser, Namespace
from collections import namedtuple

__all__ = [
'command',
'param',
'Application'
]

class CommandLine(type):
"""
Meta class that enables declarative command definitions
"""
def __new__(cls, name, bases, attrs):
instance = super(CommandLine, cls).__new__(cls, name, bases, attrs)
subcommands = []
main_command = None
for name, member in attrs.iteritems():
if hasattr(member, "command"):
main_command = member
# else if member.params:
# subcommands.append(member)
parser = None
if main_command:
parser = ArgumentParser(*main_command.command.args, **main_command.command.kwargs)
for param in main_command.params:
parser.add_argument(*param.args, **param.kwargs)


# subparsers = None
# if subcommands.length:
# subparsers = parser.add_subparsers()
#
# for command in subcommands:
#
# for param in main_command.params:
# parser.add_argument(*param.args, **param.kwargs)

instance.parser = 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, f, name='values'):
setattr(f, name, self.values)
return f

def __call__(self, f):
return self.metarate(f)


class command(metarator):
"""
Used to decorate the main entry point
"""
def __call__(self, f):
return self.metarate(f, name='command')

class param(metarator):
"""
Use this decorator instead of `ArgumentParser.add_argument`.
"""
def __call__(self, f):
f.params = f.params if hasattr(f, 'params') else []
f.params.append(self.values)
return f


class Application(object):
"""
Bare bones base class for command line applications. Hides the
meta programming complexities.
"""
__metaclass__ = CommandLine

def parse(self, argv):
return self.parser.parse_args(argv)

def run(self, args):
if hasattr(args, 'run'):
args.run(args)
else:
self.main(args)

+ 68
- 1
hyde/engine.py View File

@@ -3,7 +3,74 @@ def init(args):
print args.sitepath
print args.force
print args.template
# Ensure sitepath is okay (refer to force parameter)
# Find template by looking at the paths
# 1. Environment Variable
# 2. Hyde Data Directory
# Throw exception on failure
# Do not delete the site path, just overwrite existing files

def gen(args): pass

def serve(args): pass
def serve(args): pass

from version import __version__

# """
# Implements the hyde entry point commands
# """
# class Command(object):
# """
# Base class for hyde commands
# """
# def __init__(self, **kwargs):
# super(Command, self).__init__(epilog='Use %(prog)s {command} -h to get help on individual commands', **kwargs)
# self.subcommands = None
#
# def compose(self, commands, **kwargs):
# self.subcommands = self.add_subparsers(**kwargs)
# for command in commands:
# self.subcommands.add_parser(command)
#
# def run(self, args=None):
# """
# Executes the command
# """
# options = {}
# options.update(self.defaults)
# if args:
# options.update(args)
# self.execute(options)
#
# def execute(self):
# """
# Abstract method for the derived classes
# """
# abstract
#
# class HydeCommand(Command):
# """
# The parent command object.
# """
# def __init__(self, **kwargs):
# super(HydeCommand, self).__init__(**kwargs)
# self.add_argument('--version', action='version', version='%(prog)s ' + __version__)
# self.add_argument('-s', '--sitepath', action='store', default='.', help="Location of the hyde site")
#
#
# class Initializer(Command):
# """
# Represents the `hyde init` command
# """
# def __init__(self, parent, **kwargs):
# super(Initializer, self).__init__(**kwargs)
# 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')
#
# def run(self):
# """
#
# """
# pass

hyde/ext/templates/jinja2Template.py → hyde/ext/templates/jinja.py View File

@@ -1,19 +1,28 @@
"""
Hyde Template interface realization for Jinja2
Jinja template utilties
"""
from hyde.template import Template
from jinja2 import Environment, FileSystemLoader

# pylint: disable-msg=W0104,E0602,W0613,R0201
class Jinja2Template(Template):
def configure(self, sitepath, config):
"""
The Jinja2 Template implementation
"""
def __init__(self, sitepath):
super(Jinja2Template, self).__init__(sitepath)
self.env = Environment(loader=FileSystemLoader(sitepath))

def configure(self, config):
"""
Uses the config object to initialize the jinja environment.
"""
self.env = Environment(loader=FileSystemLoader(sitepath))
pass
def render(self, template_name, context):
"""
Renders the given template using the context
"""
t = self.env.get_template(template_name)
return t.render(context)
template = self.env.get_template(template_name)
return template.render(context)

+ 10
- 3
hyde/template.py View File

@@ -1,9 +1,16 @@
# -*- coding: utf-8 -*-
# pylint: disable-msg=W0104,E0602,W0613,R0201
"""
Interface for hyde template engines. To use a different template engine,
the following interface must be implemented.
Abstract classes and utilities for template engines
"""
class Template(object):
"""
Interface for hyde template engines. To use a different template engine,
the following interface must be implemented.
"""
def __init__(self, sitepath):
self.sitepath = sitepath

def configure(self, config):
"""
The config object is a simple YAML object with required settings. The template
@@ -12,7 +19,7 @@ class Template(object):
"""
abstract

def render(template_name, context):
def render(self, template_name, context):
"""
Given the name of a template (partial path usually), and the context, this function
must return the rendered string.


+ 36
- 0
hyde/tests/test_command_line.py View File

@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
"""
Use nose
`$ pip install nose`
`$ nosetests`
"""

from hyde.command_line import Application, command, param
from util import trap_exit
from mock import Mock, patch

@trap_exit
def test_command_basic():

number_of_calls = 0
class TestCommandLine(Application):

@command(description='test')
@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

with patch.object(TestCommandLine, '_main') as _main:
c = TestCommandLine()
args = c.parse(['--force', '--force2', 'True'])
c.run(args)

args = c.parse(['--force2', 'False'])
c.run(args)

assert _main.call_count == 2

+ 1
- 1
hyde/tests/test_jinja2template.py View File

@@ -7,7 +7,7 @@ Use nose
Code borrowed from rwbench.py from the jinja2 examples
"""
from datetime import datetime
from hyde.ext.templates.jinja2Template import Jinja2Template
from hyde.ext.templates.jinja import Jinja2Template
from hyde.fs import File, Folder
from jinja2.utils import generate_lorem_ipsum
from random import choice, randrange


+ 12
- 1
hyde/tests/util.py View File

@@ -6,4 +6,15 @@ def assert_html_equals(expected, actual, sanitize=None):
if sanitize:
expected = sanitize(expected)
actual = sanitize(actual)
assert expected == actual
assert expected == actual

def trap_exit(f):
def test_wrapper(*args):
try:
f(*args)
except SystemExit, e:
print "Error running test [%s]" % f.__name__
print e.message
raise e
return test_wrapper


+ 0
- 267
pylintrc View File

@@ -1,267 +0,0 @@
[MASTER]

# Profiled execution.
profile=no

# Add <file or directory> to the black list. It should be a base name, not a
# path. You may set this option multiple times.
#ignore=.svn

# Pickle collected data for later comparisons.
persistent=yes

# Set the cache size for astng objects.
cache-size=500

# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=


[MESSAGES CONTROL]

# Enable only checker(s) with the given id(s). This option conflicts with the
# disable-checker option
#enable-checker=

# Enable all checker(s) except those with the given id(s). This option
# conflicts with the enable-checker option
#disable-checker=design

# Enable all messages in the listed categories.
#enable-msg-cat=

# Disable all messages in the listed categories.
#disable-msg-cat=

# Enable the message(s) with the given id(s).
#enable-msg=


# Disable the message(s) with the given id(s).
# List of all available ids: http://www.logilab.org/card/pylintfeatures

# Disabled messages:
# I0011: Locally disabling %s Used when an inline option disable a message or a messages category.
disable-msg=I0011


[REPORTS]

# set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html
output-format=text

# Include message's id in output
include-ids=yes

# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no

# Tells wether to display a full report or only the messages
reports=yes

# Python expression which should return a note less than 10 (10 is the highest
# note).You have access to the variables errors warning, statement which
# respectivly contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (R0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)

# Add a comment according to your evaluation note. This is used by the global
# evaluation report (R0004).
comment=no

# Enable the report(s) with the given id(s).
#enable-report=

# Disable the report(s) with the given id(s).
#disable-report=


# checks for :
# * doc strings
# * modules / classes / functions / methods / arguments / variables name
# * number of arguments, local variables, branchs, returns and statements in
# functions, methods
# * required module attributes
# * dangerous default values as arguments
# * redefinition of function / method / class
# * uses of the global statement
#
[BASIC]

# Required attributes for module, separated by a comma
required-attributes=

# Regular expression which should only match functions or classes name which do
# not require a docstring
no-docstring-rgx=__.*__

# Regular expression which should only match correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$

# Regular expression which should only match correct module level names
const-rgx=(([A-Z_][A-Z1-9_]*)|(__.*__)|([a-z_][a-z0-9_]*))$

# Regular expression which should only match correct class names
class-rgx=[_a-zA-Z0-9]+$

# Regular expression which should only match correct function names
function-rgx=[a-z_][a-zA-Z0-9_]{2,40}$

# Regular expression which should only match correct method names
method-rgx=[a-z_][a-zA-Z0-9_]{2,40}$

# Regular expression which should only match correct instance attribute names
attr-rgx=[a-z_][a-z0-9_]{1,30}$
#alternative
#attr-rgx=([a-z_][a-z0-9_]{2,30}|([a-z_][a-zA-Z0-9]{2,30}))$

# Regular expression which should only match correct argument names
argument-rgx=[a-z_][a-z0-9_]{1,30}$

# Regular expression which should only match correct variable names
variable-rgx=[a-z_][a-zA-Z0-9_]{1,30}$

# Regular expression which should only match correct list comprehension /
# generator expression variable names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$

# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_

# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata

# List of builtins function names that should not be used, separated by a comma
bad-functions=


# try to find bugs in the code using type inference
#
[TYPECHECK]

# Tells wether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes

# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamicaly set).
ignored-classes=SQLObject

# When zope mode is activated, consider the acquired-members option to ignore
# access to some undefined attributes.
zope=no

# List of members which are usually get through zope's acquisition mecanism and
# so shouldn't trigger E0201 when accessed (need zope=yes to be considered).
acquired-members=REQUEST,acl_users,aq_parent


# checks for
# * unused variables / imports
# * undefined variables
# * redefinition of variable from builtins or from an outer scope
# * use of variable before assigment
#
[VARIABLES]

# Tells wether we should check for unused import in __init__ files.
init-import=no

# A regular expression matching names used for dummy variables (i.e. not used).
dummy-variables-rgx=_|dummy

# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=


# checks for :
# * methods without self as first argument
# * overridden methods signature
# * access only to existant members via self
# * attributes not defined in the __init__ method
# * supported interfaces implementation
# * unreachable code
#
[CLASSES]

# List of interface methods to ignore, separated by a comma. This is used for
# instance to not check methods defines in Zope's Interface base class.
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by

# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp


# checks for
# * external modules dependencies
# * relative / wildcard imports
# * cyclic imports
# * uses of deprecated modules
#
[IMPORTS]

# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,string,TERMIOS,Bastion,rexec

# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report R0402 must not be disabled)
import-graph=

# Create a graph of external dependencies in the given file (report R0402 must
# not be disabled)
ext-import-graph=

# Create a graph of internal dependencies in the given file (report R0402 must
# not be disabled)
int-import-graph=


# checks for :
# * unauthorized constructions
# * strict indentation
# * line length
# * use of <> instead of !=
#
[FORMAT]

# Maximum number of characters on a single line.
max-line-length=120

# Maximum number of lines in a module
max-module-lines=1000

# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
#indent-string=' '


# checks for:
# * warning notes in the code like TODO
# * PEP 263: source code with non ascii character but no encoding declaration
#
[MISCELLANEOUS]

# List of note tags to take in consideration, separated by a comma.
notes=TODO


# checks for similarities and duplicated code. This computation may be
# memory / CPU intensive, so you should disable it if you experiments some
# problems.
#
[SIMILARITIES]

# Minimum lines number of a similarity.
min-similarity-lines=4

# Ignore comments when computing similarities.
ignore-comments=yes

# Ignore docstrings when computing similarities.
ignore-docstrings=yes

Loading…
Cancel
Save