@@ -1,7 +1,4 @@ | |||||
Django==1.2.3 | |||||
Genshi==0.6 | |||||
Jinja2==2.5.5 | Jinja2==2.5.5 | ||||
Mako==0.3.6 | |||||
Markdown==2.0.3 | Markdown==2.0.3 | ||||
MarkupSafe==0.11 | MarkupSafe==0.11 | ||||
PyYAML==3.09 | PyYAML==3.09 | ||||
@@ -3,15 +3,17 @@ | |||||
The command line interface for hyde. | The command line interface for hyde. | ||||
""" | """ | ||||
import argparse | import argparse | ||||
from engine import init, gen, serve | |||||
from version import __version__ | from version import __version__ | ||||
from engine import init, gen, serve | |||||
def main(): | def main(): | ||||
""" | """ | ||||
The main function called by hyde executable | 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') | 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('-v', '--version', action='version', version='%(prog)s ' + __version__) | ||||
parser.add_argument('-s', '--sitepath', action='store', default='.', help="Location of the hyde site") | 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', | init_command.add_argument('-f', '--force', action='store_true', default=False, dest='force', | ||||
help='Overwrite the current site if it exists') | help='Overwrite the current site if it exists') | ||||
args = parser.parse_args() | args = parser.parse_args() | ||||
args.run(args) | |||||
args.run(args) | |||||
@@ -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) |
@@ -3,7 +3,74 @@ def init(args): | |||||
print args.sitepath | print args.sitepath | ||||
print args.force | print args.force | ||||
print args.template | 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 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 |
@@ -1,19 +1,28 @@ | |||||
""" | """ | ||||
Hyde Template interface realization for Jinja2 | |||||
Jinja template utilties | |||||
""" | """ | ||||
from hyde.template import Template | from hyde.template import Template | ||||
from jinja2 import Environment, FileSystemLoader | from jinja2 import Environment, FileSystemLoader | ||||
# pylint: disable-msg=W0104,E0602,W0613,R0201 | |||||
class Jinja2Template(Template): | 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. | Uses the config object to initialize the jinja environment. | ||||
""" | """ | ||||
self.env = Environment(loader=FileSystemLoader(sitepath)) | |||||
pass | |||||
def render(self, template_name, context): | def render(self, template_name, context): | ||||
""" | """ | ||||
Renders the given template using the 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) |
@@ -1,9 +1,16 @@ | |||||
# -*- coding: utf-8 -*- | # -*- 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): | 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): | def configure(self, config): | ||||
""" | """ | ||||
The config object is a simple YAML object with required settings. The template | The config object is a simple YAML object with required settings. The template | ||||
@@ -12,7 +19,7 @@ class Template(object): | |||||
""" | """ | ||||
abstract | 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 | Given the name of a template (partial path usually), and the context, this function | ||||
must return the rendered string. | must return the rendered string. | ||||
@@ -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 |
@@ -7,7 +7,7 @@ Use nose | |||||
Code borrowed from rwbench.py from the jinja2 examples | Code borrowed from rwbench.py from the jinja2 examples | ||||
""" | """ | ||||
from datetime import datetime | 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 hyde.fs import File, Folder | ||||
from jinja2.utils import generate_lorem_ipsum | from jinja2.utils import generate_lorem_ipsum | ||||
from random import choice, randrange | from random import choice, randrange | ||||
@@ -6,4 +6,15 @@ def assert_html_equals(expected, actual, sanitize=None): | |||||
if sanitize: | if sanitize: | ||||
expected = sanitize(expected) | expected = sanitize(expected) | ||||
actual = sanitize(actual) | 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 | |||||
@@ -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 |