class StangoTestCase(StangoTestCase): def setup(self): self.manager = Stango() def test_manager_defaults(self): self.eq(self.manager.files, Files()) self.eq(self.manager.index_file, None) def test_add_hook(self): def hook(context, data): pass self.manager.add_hook('post_render_hook', hook) self.eq(self.manager.hooks, {'post_render_hook': hook}) def test_add_hook_invalid_name(self): def hook(context, data): pass exc = self.assert_raises(ValueError, self.manager.add_hook, 'nonexistent_hook', hook) self.eq(str(exc), 'nonexistent_hook is not a valid hook name') def test_add_noncallable_hook(self): exc = self.assert_raises(TypeError, self.manager.add_hook, 'post_render_hook', 5) self.eq(str(exc), 'hook_func must be callable')
class GenerateTestCase(StangoTestCase): def setup(self): self.tmp = self.tempdir() self.manager = Stango() self.manager.index_file = 'index.html' def test_generate_simple(self): self.manager.files += [ ('', view_value('foobar')), ('barfile.txt', view_value('barfoo')), ] self.manager.generate(self.tmp) self.eq(sorted(os.listdir(self.tmp)), ['barfile.txt', 'index.html']) with open(os.path.join(self.tmp, 'index.html')) as fobj: self.eq(fobj.read(), 'foobar') with open(os.path.join(self.tmp, 'barfile.txt')) as fobj: self.eq(fobj.read(), 'barfoo') def test_generate_dest_is_non_dir(self): self.manager.files = Files( ('', dummy_view), ) dest_path = os.path.join(self.tmp, 'dest.txt') with open(dest_path, 'w') as fobj: fobj.write('foo') exc = self.assert_raises(ValueError, self.manager.generate, dest_path) self.eq(str(exc), "'%s' is not a directory" % dest_path) # Check the file wasn't modified self.eq(os.listdir(self.tmp), ['dest.txt']) with open(os.path.join(self.tmp, 'dest.txt'), 'r') as fobj: self.eq(fobj.read(), 'foo') def test_generate_outdir_exists(self): # Create a file and a directory to outdir with open(os.path.join(self.tmp, 'foo'), 'w') as fobj: fobj.write('bar') os.mkdir(os.path.join(self.tmp, 'dummydir')) self.eq(sorted(os.listdir(self.tmp)), ['dummydir', 'foo']) self.manager.files = Files( ('', view_value('baz')), ) self.manager.generate(self.tmp) # Check that the old destdir contents were removed self.eq(os.listdir(self.tmp), ['index.html']) def test_generate_different_index_file(self): self.manager.index_file = 'foofile.txt' self.manager.files += [ ('', view_value('foobar')), ('barfile.txt', view_value('barfoo')), ] self.manager.generate(self.tmp) self.eq(sorted(os.listdir(self.tmp)), ['barfile.txt', 'foofile.txt']) with open(os.path.join(self.tmp, 'foofile.txt')) as fobj: self.eq(fobj.read(), 'foobar') with open(os.path.join(self.tmp, 'barfile.txt')) as fobj: self.eq(fobj.read(), 'barfoo') def test_view_returns_a_bytes_object(self): self.manager.files = Files( ('', view_value(b'\xde\xad\xbe\xef')), ) self.manager.generate(self.tmp) self.eq(os.listdir(self.tmp), ['index.html']) with open(os.path.join(self.tmp, 'index.html'), 'rb') as fobj: self.eq(fobj.read(), b'\xde\xad\xbe\xef') def test_view_returns_a_bytearray_object(self): self.manager.files = Files( ('', view_value(bytearray(b'\xba\xdc\x0f\xfe'))), ) self.manager.generate(self.tmp) self.eq(os.listdir(self.tmp), ['index.html']) with open(os.path.join(self.tmp, 'index.html'), 'rb') as fobj: self.eq(fobj.read(), b'\xba\xdc\x0f\xfe') def test_view_returns_a_filelike_object_with_str_contents(self): self.manager.files = Files( ('', view_value(io.StringIO('foobar'))), ) self.manager.generate(self.tmp) self.eq(os.listdir(self.tmp), ['index.html']) with open(os.path.join(self.tmp, 'index.html'), 'r') as fobj: self.eq(fobj.read(), 'foobar') def test_view_returns_a_filelike_object_with_bytes_contents(self): self.manager.files = Files( ('', view_value(io.BytesIO(b'barfoo'))), ) self.manager.generate(self.tmp) self.eq(os.listdir(self.tmp), ['index.html']) with open(os.path.join(self.tmp, 'index.html'), 'r') as fobj: self.eq(fobj.read(), 'barfoo') def test_view_renders_a_template(self): self.manager.template_dirs.insert(0, self.template_path) self.manager.files = Files( ('', view_template('value.txt'), {'value': 'foobar'}) ) self.manager.generate(self.tmp) self.eq(os.listdir(self.tmp), ['index.html']) with open(os.path.join(self.tmp, 'index.html')) as fobj: self.eq(fobj.read(), 'value is: foobar') def test_no_index_file(self): self.manager.index_file = None self.manager.files = Files( ('quux/', dummy_view), ) exc = self.assert_raises(ValueError, self.manager.generate, self.tmp) self.eq(str(exc), "Directory path and no index_file: 'quux/'") def test_view_returns_None(self): self.manager.files = Files( ('', view_value(None)), ) exc = self.assert_raises(ValueError, self.manager.generate, self.tmp) self.eq(str(exc), "The result of view 'value_returner' for path '' is not a str, bytes or bytearray instance or a file-like object") def test_view_returns_an_integer(self): self.manager.files = Files( ('foo.txt', view_value(1)), ) exc = self.assert_raises(ValueError, self.manager.generate, self.tmp) self.eq(str(exc), "The result of view 'value_returner' for path 'foo.txt' is not a str, bytes or bytearray instance or a file-like object") def test_view_returns_a_filelike_object_with_invalid_contents(self): class InvalidFile(object): def read(self): return 42 self.manager.files = Files( ('', view_value(InvalidFile())), ) exc = self.assert_raises(ValueError, self.manager.generate, self.tmp) self.eq(str(exc), "Contents of the file-like object, returned by view 'value_returner' for path '', is not a str, bytes or bytearray instance") def test_post_render_hook(self): def post_render_hook(context, data): return data + b' hurr durr' self.manager.add_hook('post_render_hook', post_render_hook) self.manager.files = Files( ('', view_value('foobar')), ) self.manager.generate(self.tmp) self.eq(os.listdir(self.tmp), ['index.html']) with open(os.path.join(self.tmp, 'index.html'), 'rb') as fobj: self.eq(fobj.read(), b'foobar hurr durr') def test_post_render_hook_returns_None(self): self.manager.add_hook('post_render_hook', lambda x, y: None) self.manager.files = Files( ('', view_value('foobar')), ) exc = self.assert_raises(ValueError, self.manager.generate, self.tmp) self.eq(str(exc), 'The result of post_render_hook is not a bytes or bytearray instance for index.html')
def run(): if (len(sys.argv) < 2 or sys.argv[1] not in ['runserver', 'generate', 'quickstart']): print_help() if sys.argv[1] == 'quickstart': if len(sys.argv) != 2: print_help() sys.exit(quickstart()) if not os.path.exists('conf.py'): print('conf.py not found', file=sys.stderr) sys.exit(1) try: backup = sys.path sys.path = [''] + sys.path config = {} exec(open('conf.py').read(), config) finally: sys.path = backup for k, v in list(CONFIG_DEFAULTS.items()): config.setdefault(k, v) if 'files' not in config: print("conf.py doesn't define the 'files' variable", file=sys.stderr) sys.exit(1) manager = Stango() manager.files = config['files'] manager.index_file = config['index_file'] manager.template_dirs.insert(0, 'templates') if config['post_render_hook']: manager.add_hook('post_render_hook', config['post_render_hook']) if sys.argv[1] == 'runserver': host = '127.0.0.1' port = 8000 if len(sys.argv) == 3: if ':' in sys.argv[2]: host, port = sys.argv[2].split(':') else: port = sys.argv[2] try: port = int(port) except ValueError: print_help() elif len(sys.argv) > 3: print_help() def do_serve(): print('Starting server at http://%s:%d/' % (host, port)) httpd = manager.make_server(host, port, verbose=True) httpd.serve_forever() import stango.autoreload stango.autoreload.main(do_serve, config['autoreload']) elif sys.argv[1] == 'generate': if len(sys.argv) == 2: outdir = 'out' elif len(sys.argv) == 3: outdir = sys.argv[2] else: print_help() print('Generating to %s...' % outdir) sys.exit(manager.generate(outdir) or 0) else: print_usage()