@@ -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 | |||
@@ -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) | |||
@@ -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.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 |
@@ -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) |
@@ -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. | |||
@@ -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 | |||
""" | |||
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 | |||
@@ -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 | |||
@@ -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 |