More pecan.scaffold inline documentation and 100% test coverage.

This commit is contained in:
Ryan Petrello
2012-03-15 10:04:58 -07:00
parent bfa0e1a468
commit 6dfb7f0bb9
9 changed files with 181 additions and 14 deletions

View File

@@ -10,10 +10,30 @@ _bad_chars_re = re.compile('[^a-zA-Z0-9_]')
class PecanScaffold(object):
"""
A base Pecan scaffold. New scaffolded implementations should extend this
class and define a ``_scaffold_dir`` attribute, e.g.,
def copy_to(self, dest, **kwargs):
output_dir = os.path.abspath(os.path.normpath(dest))
pkg_name = _bad_chars_re.sub('', dest.lower())
class CoolAddOnScaffold(PecanScaffold):
_scaffold_dir = ('package', os.path.join('scaffolds', 'scaffold_name'))
...where...
pkg_resources.resource_listdir(_scaffold_dir[0], _scaffold_dir[1]))
...points to some scaffold directory root.
"""
def normalize_output_dir(self, dest):
return os.path.abspath(os.path.normpath(dest))
def normalize_pkg_name(self, dest):
return _bad_chars_re.sub('', dest.lower())
def copy_to(self, dest):
output_dir = self.normalize_output_dir(dest)
pkg_name = self.normalize_pkg_name(dest)
copy_dir(self._scaffold_dir, output_dir, {'package': pkg_name})
@@ -25,14 +45,15 @@ def copy_dir(source, dest, variables, out_=sys.stdout, i=0):
"""
Copies the ``source`` directory to the ``dest`` directory, where
``source`` is some tuple representing an installed package and a
subdirectory, e.g.,
subdirectory in the package, e.g.,
('pecan', os.path.join('scaffolds', 'base'))
('pecan_sqlalchemy', os.path.join('scaffolds', 'sqlalchemy'))
('pecan_extension', os.path.join('scaffolds', 'scaffold_name'))
``variables``: A dictionary of variables to use in any substitutions.
Substitution is performed via ``string.Template``.
``out_``: File object to write to
``out_``: File object to write to (default is sys.stdout).
"""
def out(msg):
out_.write('%s%s' % (' ' * (i * 2), msg))
@@ -77,6 +98,7 @@ def copy_dir(source, dest, variables, out_=sys.stdout, i=0):
def makedirs(directory):
""" Resursively create a named directory. """
parent = os.path.dirname(os.path.abspath(directory))
if not os.path.exists(parent):
makedirs(parent)
@@ -84,14 +106,17 @@ def makedirs(directory):
def substitute_filename(fn, variables):
""" Substitute +variables+ in file directory names. """
for var, value in variables.items():
fn = fn.replace('+%s+' % var, str(value))
return fn
def render_template(content, variables):
""" Return a bytestring representing a templated file based on the
input (content) and the variable names defined (vars)."""
"""
Return a bytestring representing a templated file based on the
input (content) and the variable names defined (vars).
"""
fsenc = sys.getfilesystemencoding()
content = native_(content, fsenc)
return bytes_(Template(content).substitute(variables), fsenc)

View File

@@ -0,0 +1 @@
Pecan ${package}

View File

@@ -0,0 +1 @@
YAR ${package}

View File

@@ -0,0 +1 @@
Pecan

View File

@@ -0,0 +1 @@
YAR

View File

@@ -0,0 +1 @@
Pecan

View File

@@ -0,0 +1 @@
YAR

View File

@@ -12,18 +12,155 @@ import pecan
if sys.version_info < (2, 7):
import unittest2 as unittest
else:
import unittest
import unittest # noqa
def has_internet():
try:
response = urllib2.urlopen('http://google.com', timeout=1)
urllib2.urlopen('http://google.com', timeout=1)
return True
except urllib2.URLError:
pass # pragma: no cover
return False
class TestPecanScaffold(unittest.TestCase):
def test_normalize_pkg_name(self):
from pecan.scaffolds import PecanScaffold
s = PecanScaffold()
assert s.normalize_pkg_name('sam') == 'sam'
assert s.normalize_pkg_name('sam1') == 'sam1'
assert s.normalize_pkg_name('sam_') == 'sam_'
assert s.normalize_pkg_name('Sam') == 'sam'
assert s.normalize_pkg_name('SAM') == 'sam'
assert s.normalize_pkg_name('sam ') == 'sam'
assert s.normalize_pkg_name(' sam') == 'sam'
assert s.normalize_pkg_name('sam$') == 'sam'
assert s.normalize_pkg_name('sam-sam') == 'samsam'
class TestScaffoldUtils(unittest.TestCase):
def setUp(self):
self.scaffold_destination = tempfile.mkdtemp()
def tearDown(self):
shutil.rmtree(self.scaffold_destination)
def test_copy_dir(self):
from pecan.scaffolds import PecanScaffold
class SimpleScaffold(PecanScaffold):
_scaffold_dir = ('pecan', os.path.join(
'tests', 'scaffold_fixtures', 'simple'
))
SimpleScaffold().copy_to(os.path.join(
self.scaffold_destination,
'someapp'
))
assert os.path.isfile(os.path.join(
self.scaffold_destination, 'someapp', 'foo'
))
assert os.path.isfile(os.path.join(
self.scaffold_destination, 'someapp', 'bar', 'spam.txt'
))
assert open(os.path.join(
self.scaffold_destination, 'someapp', 'foo'
), 'r').read().strip() == 'YAR'
assert open(os.path.join(
self.scaffold_destination, 'someapp', 'foo'
), 'r').read().strip() == 'YAR'
def test_destination_directory_levels_deep(self):
from pecan.scaffolds import copy_dir
from cStringIO import StringIO
f = StringIO()
copy_dir(('pecan', os.path.join(
'tests', 'scaffold_fixtures', 'simple'
)),
os.path.join(self.scaffold_destination, 'some', 'app'),
{},
out_=f
)
assert os.path.isfile(os.path.join(
self.scaffold_destination, 'some', 'app', 'foo')
)
assert os.path.isfile(os.path.join(
self.scaffold_destination, 'some', 'app', 'bar', 'spam.txt')
)
assert open(os.path.join(
self.scaffold_destination, 'some', 'app', 'foo'
), 'r').read().strip() == 'YAR'
assert open(os.path.join(
self.scaffold_destination, 'some', 'app', 'bar', 'spam.txt'
), 'r').read().strip() == 'Pecan'
def test_destination_directory_already_exists(self):
from pecan.scaffolds import copy_dir
from cStringIO import StringIO
f = StringIO()
copy_dir(('pecan', os.path.join(
'tests', 'scaffold_fixtures', 'simple'
)),
os.path.join(self.scaffold_destination),
{},
out_=f
)
assert 'already exists' in f.getvalue()
def test_copy_dir_with_filename_substitution(self):
from pecan.scaffolds import copy_dir
copy_dir(('pecan', os.path.join(
'tests', 'scaffold_fixtures', 'file_sub'
)),
os.path.join(
self.scaffold_destination, 'someapp'
),
{'package': 'thingy'}
)
assert os.path.isfile(os.path.join(
self.scaffold_destination, 'someapp', 'foo_thingy')
)
assert os.path.isfile(os.path.join(
self.scaffold_destination, 'someapp', 'bar_thingy', 'spam.txt')
)
assert open(os.path.join(
self.scaffold_destination, 'someapp', 'foo_thingy'
), 'r').read().strip() == 'YAR'
assert open(os.path.join(
self.scaffold_destination, 'someapp', 'bar_thingy', 'spam.txt'
), 'r').read().strip() == 'Pecan'
def test_copy_dir_with_file_content_substitution(self):
from pecan.scaffolds import copy_dir
copy_dir(('pecan', os.path.join(
'tests', 'scaffold_fixtures', 'content_sub'
)),
os.path.join(
self.scaffold_destination, 'someapp'
),
{'package': 'thingy'}
)
assert os.path.isfile(os.path.join(
self.scaffold_destination, 'someapp', 'foo')
)
assert os.path.isfile(os.path.join(
self.scaffold_destination, 'someapp', 'bar', 'spam.txt')
)
assert open(os.path.join(
self.scaffold_destination, 'someapp', 'foo'
), 'r').read().strip() == 'YAR thingy'
assert open(os.path.join(
self.scaffold_destination, 'someapp', 'bar', 'spam.txt'
), 'r').read().strip() == 'Pecan thingy'
class TestTemplateBuilds(unittest.TestCase):
"""
Used to build and test the templated quickstart project(s).
@@ -86,7 +223,7 @@ class TestTemplateBuilds(unittest.TestCase):
@unittest.skipUnless(has_internet(), 'Internet connectivity unavailable.')
@unittest.skipUnless(
getattr(pecan, '__run_all_tests__', False) is True,
'Skipping (really slow). To run, `$ python setup.py test --functional.`'
'Skipping (slow). To run, `$ python setup.py test --functional.`'
)
def test_project_pecan_serve_command(self):
pecan_exe = os.path.join(self.install_dir, 'bin', 'pecan')
@@ -113,10 +250,9 @@ class TestTemplateBuilds(unittest.TestCase):
@unittest.skipUnless(has_internet(), 'Internet connectivity unavailable.')
@unittest.skipUnless(
getattr(pecan, '__run_all_tests__', False) is True,
'Skipping (really slow). To run, `$ python setup.py test --functional.`'
'Skipping (slow). To run, `$ python setup.py test --functional.`'
)
def test_project_pecan_shell_command(self):
from pecan.testing import load_test_app
pecan_exe = os.path.join(self.install_dir, 'bin', 'pecan')
# Start the server
@@ -148,7 +284,7 @@ class TestTemplateBuilds(unittest.TestCase):
@unittest.skipUnless(has_internet(), 'Internet connectivity unavailable.')
@unittest.skipUnless(
getattr(pecan, '__run_all_tests__', False) is True,
'Skipping (really slow). To run, `$ python setup.py test --functional.`'
'Skipping (slow). To run, `$ python setup.py test --functional.`'
)
def test_project_tests_command(self):
py_exe = os.path.join(self.install_dir, 'bin', 'python')