More pecan.scaffold inline documentation and 100% test coverage.
This commit is contained in:
@@ -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)
|
||||
|
||||
0
pecan/tests/scaffold_fixtures/__init__.py
Normal file
0
pecan/tests/scaffold_fixtures/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
Pecan ${package}
|
||||
1
pecan/tests/scaffold_fixtures/content_sub/foo_tmpl
Normal file
1
pecan/tests/scaffold_fixtures/content_sub/foo_tmpl
Normal file
@@ -0,0 +1 @@
|
||||
YAR ${package}
|
||||
@@ -0,0 +1 @@
|
||||
Pecan
|
||||
1
pecan/tests/scaffold_fixtures/file_sub/foo_+package+
Normal file
1
pecan/tests/scaffold_fixtures/file_sub/foo_+package+
Normal file
@@ -0,0 +1 @@
|
||||
YAR
|
||||
1
pecan/tests/scaffold_fixtures/simple/bar/spam.txt
Normal file
1
pecan/tests/scaffold_fixtures/simple/bar/spam.txt
Normal file
@@ -0,0 +1 @@
|
||||
Pecan
|
||||
1
pecan/tests/scaffold_fixtures/simple/foo
Normal file
1
pecan/tests/scaffold_fixtures/simple/foo
Normal file
@@ -0,0 +1 @@
|
||||
YAR
|
||||
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user