def render(template, context=None, **kwargs): """ Return the given template string rendered using the given context. """ renderer = Renderer() return renderer.render(template, context, **kwargs)
def test(self): template = testData['template'] partials = testData.has_key('partials') and testData['partials'] or {} expected = testData['expected'] data = testData['data'] # Convert code strings to functions. # TODO: make this section of code easier to understand. new_data = {} for key, val in data.iteritems(): if isinstance(val, dict) and val.get('__tag__') == 'code': val = eval(val['python']) new_data[key] = val renderer = Renderer(partials=partials) actual = renderer.render(template, new_data) actual = actual.encode('utf-8') message = """%s Template: \"""%s\""" Expected: %s Actual: %s Expected: \"""%s\""" Actual: \"""%s\""" """ % (description, template, repr(expected), repr(actual), expected, actual) self.assertEquals(actual, expected, message)
def render(template, context=None, name=None, **kwargs): """ Return the given template string rendered using the given context. """ renderer = Renderer() parsed_template = parse(template, name=name) return renderer.render(parsed_template, context, **kwargs)
def crear_plantilla(archivo_fuente='user.c'): print "creando plantilla para archivo %s" % archivo_fuente renderer = Renderer() template = renderer.load_template(SOURCE_TEMPLATE) dato_plantilla = renderer.render(template, {'include_path': archivo_fuente}) archivo = open(SOURCE_FILE, 'w') archivo.write(dato_plantilla) archivo.close() print "plantilla creada"
def main(sys_argv=sys.argv): template, context, c_format, multiple = parse_args(sys_argv, USAGE) if template.endswith('.mustache'): template = template[:-9] renderer = Renderer() try: template = renderer.load_template(template) except TemplateNotFoundError: pass if context.endswith(".csv") or (c_format and (c_format == "csv")): try: context = csv.DictReader(open(context, 'rb'))#, delimiter=',', quotechar='"') except IOError: print('ERROR: Could not parse context as CSV file. Check usage for input format options') exit(-1) else: try: context = json.load(open(context)) except IOError: context = json.loads(context) except ValueError: #likely a not well-formed JSON string, or user forgot -f csv. print('ERROR: Could not parse context as JSON file or text, check usage for input format options') exit(1) if (multiple): print ("multiple render on field %s" % multiple) fileName, fileExt = os.path.splitext(multiple) for i,c in enumerate(context): if multiple in c: f_name = str(c[multiple]) else: f_name = "%s-%03d%s" % (fileName, i, fileExt) with open(f_name, "w") as f: # mode "wx" could be used to prevent overwriting, + pass IOError, adding "--force" option to override. rendered = renderer.render(template, c) f.write(rendered) print ("%s done") % f_name else: rendered = renderer.render(template, context) print rendered
def get(self): pass_phrase = self.authenticate_request() if pass_phrase: if self.check_setup(): loader = Loader(extension='html', search_dirs=['view', 'view/setup']) renderer = Renderer(file_extension='html', search_dirs=['view/partials', 'view/setup']) template = loader.load_name('setup') html = renderer.render(template, {"pass": pass_phrase}) self.write(html) else: self.write("setup already completed.")
def get(self, article_name): article_name = article_name.lower() if article_name in BaseController.articles: article = BaseController.articles[article_name] # if content has not modified since last request # send a 304 not modified status modified_header_key = "If-Modified-Since" if modified_header_key in self.request.headers: if (self.request.headers["If-Modified-Since"] == article['modified_date']): self.set_status(304) return if (BaseController.settings['enable_caching'] and article_name in BaseController.cached_articles): html = BaseController.cached_articles[article_name] else: view_model = { "article": article, "site_name": BaseController.settings['site_name'] } self.attach_meta_data(view_model) loader = Loader(file_encoding='utf8', extension='html', search_dirs=[ 'view', ]) renderer = Renderer(file_encoding='utf8', file_extension='html', search_dirs=['view/partials']) template = loader.load_name('article') html = renderer.render(template, view_model) # cache the html BaseController.cached_articles[article_name] = html # set http caching headers if "http_caching_max_age" in BaseController.settings: max_age = BaseController.settings["http_caching_max_age"] else: max_age = 60 self.set_header("Cache-control", "max-age=%s" % max_age) self.set_header("Last-Modified", article['modified_date']) self.write(html) else: raise tornado.web.HTTPError(404)
def get(self, article_name): article_name = article_name.lower() if article_name in BaseController.articles: article = BaseController.articles[article_name] # if content has not modified since last request # send a 304 not modified status modified_header_key = "If-Modified-Since" if modified_header_key in self.request.headers: if (self.request.headers["If-Modified-Since"] == article['modified_date']): self.set_status(304) return if (BaseController.settings['enable_caching'] and article_name in BaseController.cached_articles): html = BaseController.cached_articles[article_name] else: view_model = { "article": article, "site_name": BaseController.settings['site_name'] } self.attach_meta_data(view_model) loader = Loader(file_encoding='utf8', extension='html', search_dirs=['view', ]) renderer = Renderer(file_encoding='utf8', file_extension='html', search_dirs=['view/partials']) template = loader.load_name('article') html = renderer.render(template, view_model) # cache the html BaseController.cached_articles[article_name] = html # set http caching headers if "http_caching_max_age" in BaseController.settings: max_age = BaseController.settings["http_caching_max_age"] else: max_age = 60 self.set_header("Cache-control", "max-age=%s" % max_age) self.set_header("Last-Modified", article['modified_date']) self.write(html) else: raise tornado.web.HTTPError(404)
def get(self): pass_phrase = self.authenticate_request() if pass_phrase: if self.check_setup(): loader = Loader(extension='html', search_dirs=['view', 'view/setup']) renderer = Renderer( file_extension='html', search_dirs=['view/partials', 'view/setup']) template = loader.load_name('setup') html = renderer.render(template, {"pass": pass_phrase}) self.write(html) else: self.write("setup already completed.")
def generate_page(self, articles): view_model = { "articles": articles, "site_name": BaseController.settings["site_name"] } self.attach_meta_data(view_model) loader = Loader(file_encoding='utf8', extension='html', search_dirs=['view', ]) renderer = Renderer(file_encoding='utf8', file_extension='html', search_dirs=['view/partials']) template = loader.load_name('list') html = renderer.render(template, view_model) return html
def render(self, content, data): """ Render the given ``content`` as template with the ``data`` dictionary. Args: content (str): The template content to render. data (dict): The data dictionary to render. Returns: str: The rendered template text """ stache = Renderer(partials=self._partials_loader) return stache.render(content, data)
def render(self, data_dict, template): """ Take a data dictionary and render it using the given template file. Required Arguments: :param data_dict: The data dictionary to render. :param template: The path to the template, after the ``template_module`` or ``template_dirs`` prefix as defined in the application. :returns: str (the rendered template text) """ LOG.debug("rendering output using '%s' as a template." % template) content = self.load_template(template) stache = Renderer(partials=self._partials_loader) return stache.render(content, data_dict)
def render(template, context, out): renderer = Renderer(file_encoding="utf-8") try: template = renderer.load_template(template) except TemplateNotFoundError: pass try: context = json.load(open(context)) except IOError: context = json.loads(context) rendered = renderer.render(template, context) file = codecs.open(out, "w", "utf-8") file.write(rendered) file.close()
def generate_page(self, articles): view_model = { "articles": articles, "site_name": BaseController.settings["site_name"] } self.attach_meta_data(view_model) loader = Loader(file_encoding='utf8', extension='html', search_dirs=[ 'view', ]) renderer = Renderer(file_encoding='utf8', file_extension='html', search_dirs=['view/partials']) template = loader.load_name('list') html = renderer.render(template, view_model) return html
def get(self): if (BaseController.settings['enable_caching'] and BaseController.cached_home): html = BaseController.cached_home self.write(html) else: published_articles = [] for article in BaseController.articles.values(): if article['date'] is not None: published_articles.append(article) articles = sorted(published_articles, key=operator.itemgetter("date"), reverse=True) max_articles_count = BaseController.settings[ "homepage_max_articles"] show_archive = False if len(articles) > max_articles_count: show_archive = True articles = articles[0:max_articles_count] view_model = { "articles": articles, "showArchive": show_archive, "site_name": BaseController.settings["site_name"] } self.attach_meta_data(view_model) loader = Loader(file_encoding='utf8', extension='html', search_dirs=[ 'view', ]) renderer = Renderer(file_encoding='utf8', file_extension='html', search_dirs=['view/partials']) template = loader.load_name('home') html = renderer.render(template, view_model) # cache the home page BaseController.cached_home = html self.write(html)
def _runTest(self): context = self._context description = self._description expected = self._expected file_path = self._file_path partials = self._partials template = self._template test_name = self._test_name renderer = Renderer(partials=partials) actual = renderer.render(template, context) # We need to escape the strings that occur in our format string because # they can contain % symbols, for example (in delimiters.yml)-- # # "template: '{{=<% %>=}}(<%text%>)'" # def escape(s): return s.replace("%", "%%") parser_info = _get_parser_info() subs = [ repr(test_name), description, os.path.abspath(file_path), template, repr(context), parser_info ] subs = tuple([escape(sub) for sub in subs]) # We include the parsing module version info to help with troubleshooting # yaml/json/simplejson issues. message = """%s: %s File: %s Template: \"""%s\""" Context: %s %%s [using %s] """ % subs self.assertString(actual, expected, format=message)
def main(sys_argv): template, context = parse_args(sys_argv, USAGE) if template.endswith('.mustache'): template = template[:-9] renderer = Renderer() try: template = renderer.load_template(template) except IOError: pass try: context = json.load(open(context)) except IOError: context = json.loads(context) rendered = renderer.render(template, context) print rendered
def main(sys_argv=sys.argv): template, context = parse_args(sys_argv, USAGE) if template.endswith('.mustache'): template = template[:-9] renderer = Renderer() try: template = renderer.load_template(template) except IOError: pass try: context = json.load(open(context)) except IOError: context = json.loads(context) rendered = renderer.render(template, context) print rendered
def main(argv=None): if argv is None: argv = sys.argv template, context, options = parse_args(argv, USAGE) if context is None and not sys.stdin.isatty(): user_context, _ = read_yaml_frontmatter(sys.stdin) elif context: content = arg2text(context) user_context, _ = extract_context(content, greedy=True) else: user_context = {} # assuming first arg is a filename or template literal template = arg2text(template) template_context, template = extract_context(template) template_context.update(user_context) renderer = Renderer() rendered = renderer.render(template, template_context) print(rendered.encode('utf-8'))
def _runTest(self): context = self._context description = self._description expected = self._expected file_path = self._file_path partials = self._partials template = self._template test_name = self._test_name renderer = Renderer(partials=partials) actual = renderer.render(template, context) # We need to escape the strings that occur in our format string because # they can contain % symbols, for example (in delimiters.yml)-- # # "template: '{{=<% %>=}}(<%text%>)'" # def escape(s): return s.replace("%", "%%") parser_info = _get_parser_info() subs = [repr(test_name), description, os.path.abspath(file_path), template, repr(context), parser_info] subs = tuple([escape(sub) for sub in subs]) # We include the parsing module version info to help with troubleshooting # yaml/json/simplejson issues. message = """%s: %s File: %s Template: \"""%s\""" Context: %s %%s [using %s] """ % subs self.assertString(actual, expected, format=message)
def get(self): if (BaseController.settings['enable_caching'] and BaseController.cached_home): html = BaseController.cached_home self.write(html) else: published_articles = [] for article in BaseController.articles.values(): if article['date'] is not None: published_articles.append(article) articles = sorted(published_articles, key=operator.itemgetter("date"), reverse=True) max_articles_count = BaseController.settings["homepage_max_articles"] show_archive = False if len(articles) > max_articles_count: show_archive = True articles = articles[0:max_articles_count] view_model = { "articles": articles, "showArchive": show_archive, "site_name": BaseController.settings["site_name"] } self.attach_meta_data(view_model) loader = Loader(file_encoding='utf8', extension='html', search_dirs=['view', ]) renderer = Renderer(file_encoding='utf8', file_extension='html', search_dirs=['view/partials']) template = loader.load_name('home') html = renderer.render(template, view_model) # cache the home page BaseController.cached_home = html self.write(html)
def test(self): template = testData['template'] partials = testData.has_key('partials') and testData['partials'] or {} expected = testData['expected'] data = testData['data'] renderer = Renderer(partials=partials) actual = renderer.render(template, data) actual = actual.encode('utf-8') message = """%s Template: \"""%s\""" Expected: %s Actual: %s Expected: \"""%s\""" Actual: \"""%s\""" """ % (description, template, repr(expected), repr(actual), expected, actual) self.assertEquals(actual, expected, message)
def compile_config_file(outfile): """ Compile the config file, replacing all templated variables with their values outfile is a file-like object to write the compiled template into """ print('Compiling {0}'.format(NGINX_CONFIG)) with open(NGINX_CONFIG) as config_file: template = parse_template( config_file.read(), delimiters=DELIMITERS ) ## Check that all the environment variables ## defined in the config file exist for node in template._parse_tree: if not isinstance(node, str): key = node.key _check_envvar_exists(key) renderer = Renderer() context = dict(os.environ) context.update(DJANGO_SETTINGS) output = renderer.render(template, context) with open(outfile, 'w+b') as f: f.write(bytes(output, encoding='utf-8'))
class MustacheEngine(TemplateEngine): """ Mustache template engine. """ def __init__(self, **kw): """ Initialize the template renderer. :param directories: Keyword parameter. A list of directories used as the search path for templates. """ self.renderer = Renderer(search_dirs=kw['directories']) TemplateEngine.__init__(self, **kw) def get_template(self, name, **kw): """ Get a template. :param name: The name of the template. """ parts = name.rsplit('.', 2) if len(parts) > 1 and parts[1] == 'mustache': name = parts[0] return self.renderer.load_template(name) def render(self, name, **kw): """ Render a template. :param name: The name of the template. :param **kw: The values to substitute in the template. """ template = self.templates.get(name, None) return self.renderer.render(template, kw)
def get(self): loader = Loader(extension='html', search_dirs=['view', 'view/setup']) template = loader.load_name('success') renderer = Renderer(file_extension='html', search_dirs=['view/partials', 'view/setup']) self.write(renderer.render(template, ""))
def render(self, *context, **kwargs): renderer = Renderer(search_dirs=[thisDir()]) template = renderer.load_template('govuk_template') return renderer.render(template, *context, **kwargs)
def main(argv=None): if argv is None: argv = sys.argv template, context, options = parse_args(argv, USAGE) if context is None and not sys.stdin.isatty(): user_context, _ = read_yaml_frontmatter(sys.stdin) elif context: content = arg2text(context) user_context, _ = extract_context(content, greedy=True) else: user_context = {} # assuming first arg is a filename or template literal template = arg2text(template) template_context, template = extract_context(template) template_context.update(user_context) renderer = Renderer() rendered = renderer.render(template, template_context) print(rendered.encode('utf-8')) renderer = Renderer() try: template = renderer.load_template(template) except TemplateNotFoundError: pass if context.endswith(".csv") or (c_format and (c_format == "csv")): try: context = csv.DictReader(open( context, 'rb')) #, delimiter=',', quotechar='"') except IOError: print( 'ERROR: Could not parse context as CSV file. Check usage for input format options' ) exit(-1) else: try: context = json.load(open(context)) except IOError: context = json.loads(context) except ValueError: #likely a not well-formed JSON string, or user forgot -f csv. print( 'ERROR: Could not parse context as JSON file or text, check usage for input format options' ) exit(1) if (multiple): print("multiple render on field %s" % multiple) fileName, fileExt = os.path.splitext(multiple) for i, c in enumerate(context): if multiple in c: f_name = str(c[multiple]) else: f_name = "%s-%03d%s" % (fileName, i, fileExt) with open( f_name, "w" ) as f: # mode "wx" could be used to prevent overwriting, + pass IOError, adding "--force" option to override. rendered = renderer.render(template, c) f.write(rendered) print("%s done") % f_name else: rendered = renderer.render(template, context) print rendered
def prepare_dcos_package_install(self, _args): args = list(_args) if len(args) == 0 or args[0] != 'package' or 'install' not in args: return args, None, None # if we have an dcos package install command, check to see if we have # an options file - supported package package = args[-1] if package[0:2] == "--": # can't find package, return print "Unsupported package or bad command: {}".format( " ".join(args)) return args, None, None if "--cli" in args and not "--app" in args: print "Not using options for cli install" return args, None, None # prepare dcos packages # to work around for Mesos-DNS, we need to create an options file # for each DCOS package we install # this file is rendered into # ~/.cellos/generated/<cell-name>/<package>_dcos_options.json # DCOS can describe a package configuration schema, with default values # Take it and recreate an actual configuration out of it pkg = dcos.package.resolve_package(package) if pkg is None: raise ValueError( 'package "{}" not found. Check spelling or update ' 'package sources.'.format(package)) pkg_config = pkg.config_json(pkg.latest_package_revision()) def config_remapper(src): """ Parses a DCOS configuration specification (config.json) and outputs a tree with the templated configuration pieces Example: https://github.com/mesosphere/universe/blob/version-2.x/repo/packages/K/kafka/3/config.json """ dest = {} for k, v in src["properties"].iteritems(): if v["type"] == "object": tmp = config_remapper(v) if len(tmp) > 0: dest[k] = tmp elif v["type"] == "string" and "default" in v: dest[k] = v["default"] dest[k] = dest[k].replace("master.mesos:2181", "{{zk}}") dest[k] = dest[k].replace("master.mesos:5050", "{{mesos}}") dest[k] = dest[k].replace("master.mesos:8080", "{{marathon}}") dest[k] = dest[k].replace( ".marathon.mesos", ".gw.{{cell}}.metal-cell.adobe.io") return dest template = config_remapper(pkg_config) cell_config_yaml = yaml.load(readify(self.tmp("config.yaml"))) renderer = Renderer(missing_tags=DECODE_ERRORS) try: package_cell_options = json.loads( renderer.render(json.dumps(template, indent=2), cell_config_yaml)) except KeyNotFoundError as e: input = json.dumps(cell_config_yaml, indent=2) raise Exception( "Failed to render template {} \n using \n{}\n{}".format( template, input, e)) options_file = self.tmp("{}.json".format(package)) # try to append options to the command if '--options' in args: print "Command already contains --options, merging options file !!!" opts_file_index = args.index("--options") + 1 user_options = json.loads(readify(args[opts_file_index])) aggregated_options = deep_merge(dict(package_cell_options), user_options) args[opts_file_index] = options_file else: print "Adding package install options" aggregated_options = package_cell_options args.insert(-1, "--options=" + options_file) with open(options_file, "wb+") as outf: outf.write(json.dumps(aggregated_options, indent=4)) outf.flush() # display the contents of the config file in its final form print("Options file content: \n{}".format( json.dumps(aggregated_options, indent=4))) return args, aggregated_options, options_file
def main(): args = docopt(__doc__) config = ConfigParser.SafeConfigParser() config.read(args['--config']) palette_urls = config.get('palettes', 'url') palette_ids = [ int(x) for x in re.findall('palette/([0-9]+)/', palette_urls) ] renderer = Renderer() if config.has_option('palettes', 'template'): template_file = config.get('palettes', 'template') f = open(template_file, 'r') template = f.read() f.close() else: template = """ {{#palettes}} /** Colourlovers Palette {{title}} {{url}} by: {{user_name}} {{description}} **/ {{#colors}} /* {{title}} */ @color-{{normalized_title}}: {{hex}}; {{/colors}} {{/palettes}} """ d = {'palettes': []} cl = ColourLovers() for palette_id in palette_ids: for palette in cl.palette(palette_id): colors = [] for hexcolor in palette.colours: c = cl.color(hexcolor)[0] a_colour = { 'badge_url': c.badge_url, 'date_created': c.date_created, 'description': c.description, 'hex': c.hex, 'hsv': c.hsv, 'id': c.id, 'image_url': c.image_url, 'rgb': c.rgb, 'title': c.title, 'normalized_title': re.sub('[^a-z_-]', '', c.title.lower()), 'url': c.url, 'user_name': c.user_name, } colors.append(a_colour) d['palettes'].append({ 'badge_url': palette.badge_url, 'date_created': palette.date_created, 'description': palette.description, 'id': palette.id, 'image_url': palette.image_url, 'title': palette.title, 'normalized_title': re.sub('[^a-z_-]', '', palette.title.lower()), 'url': palette.url, 'user_name': palette.user_name, 'colors': colors, }) ctx = ContextStack(d) css_file = config.get('palettes', 'css') c = open(css_file, 'w') c.write(renderer.render(template, ctx)) c.close()
class Whizker: """ A template manager. """ def __init__(self, templates_path, dest_path, var_set_path=None, use_env_vars=False, variables=[], ignores=None, watch_command=None): self.init_params = locals() # Save locals for later self.watch_paths = set() # List of paths to watch self.renderer = Renderer( missing_tags=MissingTags.strict, # Alert on missing vars escape=lambda x: x, # Don't escape ) self.observer = Observer() self.watch_command = watch_command # Check paths if os.path.exists(templates_path): self.templates_path = templates_path self.watch_paths.add(templates_path) else: raise FileNotFoundError(templates_path, "templates path") if os.path.exists(dest_path): self.dest_path = dest_path else: raise FileNotFoundError(dest_path, "destination path") if not var_set_path or os.path.exists(var_set_path): self.var_set_path = var_set_path else: raise FileNotFoundError(var_set_path, "variable set path") # Initial setup self.refresh_variables() def refresh_variables(self): self.variables = {} # {variable: value} self.ignores = set() # Set of regexes self.variables_rendered = False # Whether or not variables have been # shallowly rendered if self.init_params['use_env_vars']: self.variables.update(dict(os.environ)) for name in self.init_params['variables']: self.add_variables(name) if self.init_params['ignores']: self.add_ignores(self.init_params['ignores']) def add_variables(self, name): # If it might be just a name... if self.var_set_path and not os.path.exists(name): name = os.path.join(self.var_set_path, '%s.yaml' % name) try: with codecs.open(name, 'r', 'utf-8') as f: to_merge = yaml.load(f.read()) except IOError: raise FileNotFoundError(name, "variables file") except yaml.parser.ParserError as e: raise FileParseError(name, e) else: self.watch_paths.add(name) if isinstance(to_merge, dict): logger.info("Using \"%s\"..." % name) deep_update_dict(self.variables, to_merge) else: raise FileParseError(name, "not in mapping format") def render_variables(self): """ Shallowly resolves variables within variables, then evals content in {`...`} """ rendered_variables = {} for k, v in iter(self.variables.items()): if isinstance(v, str): try: v = self.renderer.render(v, self.variables) except KeyNotFoundError as e: logger.error(VariableRenderError(k, e)) # Eval {`...`} for expr in re.findall(r'{`.*?`}', v): try: v = v.replace(expr, str(eval(expr[2:-2]))) except Exception as e: logger.error(VariableRenderError(k, e)) rendered_variables[k] = v self.variables.update(rendered_variables) self.variables_rendered = True def add_ignores(self, name): try: with codecs.open(name, 'r', 'utf-8') as f: to_merge = yaml.load(f.read()) except IOError: raise FileNotFoundError(name, "ignores file") except yaml.parser.ParserError as e: raise FileParseError(e, name) else: self.watch_paths.add(name) if isinstance(to_merge, list): self.ignores |= set(re.compile(i) for i in to_merge) else: raise FileParseError(name, "not in scalar format") def should_ignore(self, name): """ Check if a name should be ignored according to self.ignores """ for pattern in self.ignores: if pattern.match(name): return True return False @property def var_sets(self): """ Yield the available variable sets """ # Does our folder exist? if self.var_set_path: # Get all the paths... for name in os.listdir(self.var_set_path): if not self.should_ignore(name): path = os.path.join(self.var_set_path, name) if os.path.isfile(path): # Yield without .yaml yield re.sub(r'\.%s$' % TEMPLATE_EXT, '', name) else: raise ValueError("No variable set path to list from.") @property def render_pairs(self): """ Yield pairs of (template file, destination file) """ for root, subdirs, files in os.walk(self.templates_path): # Substitute the template dir for home dir dest_root = re.sub(r'^%s' % self.templates_path, self.dest_path, root) # Iterate through templates for name in files: if not self.should_ignore(name): template = os.path.join(root, name) dest = os.path.join(dest_root, name) yield (template, dest) def render(self): """ Yield tuples of (destination file, mode, what to write). If there is a file render error, log it. """ if not self.variables_rendered: self.render_variables() for template, dest in self.render_pairs: try: with codecs.open(template, 'r', 'utf-8') as f: yield (dest, os.stat(template).st_mode, self.renderer.render(f.read(), self.variables)) except KeyNotFoundError as e: logger.error(FileRenderError(template, e)) except IOError as e: logger.error(FileNotFoundError(template, e)) def render_and_write(self): for dest, mode, result in self.render(): # Delete any existing file first try: os.remove(dest) except OSError: pass with make_dirs_and_open(dest) as f: f.write(result) os.chmod(dest, mode) logger.info("Successfully rendered \"%s\"" % dest) def diff(self): for dest, mode, result in self.render(): try: with codecs.open(dest, 'r', 'utf-8') as f: yield unified_diff( result.splitlines(True), f.readlines(), fromfile=dest, tofile='%s (rendered)' % dest) except IOError: yield [ "=== No destination file \"%s\" for comparison.\n" % dest] def watch(self): # Because of read-only closures scope = Scope() scope.timer = None def make_handler(file_to_watch=None): def rerender(): logger.info("\nRe-rendering...") self.refresh_variables() # If there is no resulting difference, skip if deep_iter_empty(self.diff()): logger.info("\nNo difference detected - skipping") return self.render_and_write() # Execute watch command if self.watch_command: logger.info("\nExecuting watch command: %s" % self.watch_command) call(self.watch_command, shell=True) def schedule_rerender(event): # If we have a specific file, check for it if file_to_watch: # If the file is gone, skip if not os.path.exists(file_to_watch) or \ not os.path.exists(event.src_path): return # If we don't care about the file, skip if not os.path.samefile(file_to_watch, event.src_path): return # If it's a directory, skip if event.is_directory: return # If we should ignore the file, skip if self.should_ignore(event.src_path): return logger.info("\nChange detected: \"%s\" (%s)" % (event.src_path, event.event_type)) if scope.timer: scope.timer.cancel() scope.timer = None scope.timer = Timer(WATCH_TIMEOUT, rerender) scope.timer.start() return AllEventsHandler(schedule_rerender) dir_handler = make_handler() for path in self.watch_paths: if os.path.isdir(path): self.observer.schedule( dir_handler, os.path.realpath(path), # Watch out for symlinks... recursive=True) else: # Watch the parent directory for the file pattern self.observer.schedule( make_handler(path), os.path.realpath(os.path.dirname(path)), recursive=False) self.observer.start() def stop_watch(self): self.observer.stop() def join_watch(self): self.observer.join()
def main(): args = docopt(__doc__) config = ConfigParser.SafeConfigParser() config.read(args['--config']) palette_urls = config.get('palettes', 'url') palette_ids = [int(x) for x in re.findall('palette/([0-9]+)/', palette_urls)] renderer = Renderer() if config.has_option('palettes', 'template'): template_file = config.get('palettes', 'template') f = open(template_file, 'r') template = f.read() f.close() else: template = """ {{#palettes}} /** Colourlovers Palette {{title}} {{url}} by: {{user_name}} {{description}} **/ {{#colors}} /* {{title}} */ @color-{{normalized_title}}: {{hex}}; {{/colors}} {{/palettes}} """ d = { 'palettes':[] } cl = ColourLovers() for palette_id in palette_ids: for palette in cl.palette(palette_id): colors = [] for hexcolor in palette.colours: c = cl.color(hexcolor)[0] a_colour = { 'badge_url': c.badge_url, 'date_created': c.date_created, 'description': c.description, 'hex': c.hex, 'hsv': c.hsv, 'id': c.id, 'image_url': c.image_url, 'rgb': c.rgb, 'title': c.title, 'normalized_title': re.sub('[^a-z_-]', '', c.title.lower()), 'url': c.url, 'user_name': c.user_name, } colors.append(a_colour) d['palettes'].append({ 'badge_url': palette.badge_url, 'date_created': palette.date_created, 'description': palette.description, 'id': palette.id, 'image_url': palette.image_url, 'title': palette.title, 'normalized_title': re.sub('[^a-z_-]', '', palette.title.lower()), 'url': palette.url, 'user_name': palette.user_name, 'colors':colors, }) ctx = ContextStack(d) css_file = config.get('palettes', 'css') c = open(css_file, 'w') c.write( renderer.render(template, ctx) ) c.close()