def sanitize_image(link): """ Patched function to resolve the url using Lektor. """ if get_ctx() and get_ctx().record is not None: url = url_parse(link) if not url.scheme: return get_ctx().record.url_to(link, alt=PRIMARY_ALT, base_url=get_ctx().base_url) return link
def __render(self): # When the markdown instance is attached to a cached object we can # end up in the situation where the context changed from the time # we were put into the cache to the time where we got referenced # by something elsewhere. In that case we need to re-process our # markdown. For instance this affects relative links. if self.__html is None or self.__cached_for_ctx != get_ctx(): self.__html, self.__meta = markdown_to_html(self.source, self.__record()) self.__cached_for_ctx = get_ctx()
def get_item_body(item, field, body_template): if field not in item: raise RuntimeError('Body field %r not found in %r' % (field, item)) if body_template: rv = get_ctx().env.render_template(body_template, get_ctx().pad, this=item, values={'body': item[field]}) return text_type(rv) else: with get_ctx().changed_base_url(item.url_path): return text_type(escape(item[field]))
def __render(self): # When the markdown instance is attached to a cached object we can # end up in the situation where the context changed from the time # we were put into the cache to the time where we got referenced # by something elsewhere. In that case we need to re-process our # markdown. For instance this affects relative links. if self.__html is None or \ self.__cached_for_ctx != get_ctx(): self.__html, self.__meta = markdown_to_html( self.source, self.__record()) self.__cached_for_ctx = get_ctx()
def build_artifact(self, artifact): data = {'pages': []} for page in self.get_all_children(): data['pages'].append({ 'title': self.join_fields(page, self.source.title), 'text': self.join_fields(page, self.source.text), 'tags': self.join_fields(page, self.source.tags), 'url': page.url_path }) get_ctx().record_dependency(artifact.artifact_name) with artifact.open('wb') as f: f.write(dumps(data).encode('utf-8'))
def __render(self): # When the markdown instance is attached to a cached object we can # end up in the situation where the context changed from the time # we were put into the cache to the time where we got referenced # by something elsewhere. In that case we need to re-process our # markdown. For instance this affects relative links. if self.__html is None or \ self.__cached_for_ctx != get_ctx(): self.__html, __resources = notebook_to_html( self.source, self.__record()) self.__cached_for_ctx = get_ctx() if 'inlining' in __resources: css_strs = __resources['inlining'].get('css') if css_strs: self.__meta = '\n'.join(css_strs)
def rst_to_html(text, extra_params, record): ctx = get_ctx() if ctx is None: raise RuntimeError('Context is required for markdown rendering') pub = docutils.core.Publisher( destination_class=docutils.io.StringOutput) pub.set_components('standalone', 'restructuredtext', 'html') pub.process_programmatic_settings(None, extra_params, None) pub.set_source( source=StringIO(text), source_path=record.source_filename if record is not None else None) pub.publish() metadata = {} for docinfo in pub.document.traverse(docutils.nodes.docinfo): for element in docinfo.children: if element.tagname == 'field': name_elem, body_elem = element.children name = name_elem.astext() value = body_elem.astext() else: name = element.tagname value = element.astext() name = name.lower() if name == 'date': value = datetime.datetime.strptime(value, "%Y-%m-%d %H:%M") metadata[name] = value parts = pub.writer.parts body = parts['html_title'] + parts['html_subtitle'] + parts['fragment'] return body, metadata
def render_template_into(self, template_name, this, **extra): """Render a template into the artifact and an amp subartifact.""" values = extra.get('values', {}) values['canonical'] = self.artifact_name values['amp_path'] = '' extra['values'] = values if self.dst_filename.endswith('.html'): amp_path = '/amp/{}'.format(self.artifact_name) values['amp_path'] = amp_path rv2 = self.build_state.env.render_template( 'amp-{}'.format(template_name), self.build_state.pad, this=this, **extra) ctx = get_ctx() @ctx.sub_artifact(amp_path) def build_ampsite(artifact): artifact.sources = self.sources with artifact.open('w') as f: f.write(rv2.encode('utf-8') + b'\n') rv = self.build_state.env.render_template( template_name, self.build_state.pad, this=this, **extra) with self.open('wb') as f: f.write(rv.encode('utf-8') + b'\n')
def build_artifact(self, artifact): ctx = get_ctx() source_out = self.build_state.make_named_temporary("less") map_out = self.build_state.make_named_temporary("less-sourcemap") here = os.path.dirname(self.source.source_filename) cmdline = [ "lessc", "--no-js", "--include-path=%s" % here, "--source-map=%s" % map_out, self.source.source_filename, source_out, ] reporter.report_debug_info("lessc cmd line", cmdline) proc = portable_popen(cmdline) if proc.wait() != 0: raise RuntimeError("lessc failed") with open(map_out) as f: dep_base = os.path.dirname(map_out) for dep in json.load(f).get("sources") or (): ctx.record_dependency(os.path.join(dep_base, dep)) artifact.replace_with_file(source_out)
def build_artifact(self, artifact): ctx = get_ctx() source_out = self.build_state.make_named_temporary('less') map_out = self.build_state.make_named_temporary('less-sourcemap') here = os.path.dirname(self.source.source_filename) exe = self.build_state.config['LESSC_EXECUTABLE'] if exe is None: exe = 'lessc' cmdline = [exe, '--no-js', '--include-path=%s' % here, '--source-map=%s' % map_out, self.source.source_filename, source_out] reporter.report_debug_info('lessc cmd line', cmdline) proc = portable_popen(cmdline) if proc.wait() != 0: raise RuntimeError('lessc failed') with open(map_out) as f: for dep in json.load(f).get('sources') or (): ctx.record_dependency(os.path.join(here, dep)) artifact.replace_with_file(source_out) @ctx.sub_artifact(artifact_name=artifact.artifact_name + '.map', sources=[self.source.source_filename]) def build_less_sourcemap_artifact(artifact): artifact.replace_with_file(map_out)
def get_disqus_config(self, identifier=None, url=None, title=None, category_id=None): configs = [] ctx = get_ctx() if identifier is None: if ctx.source is not None and ctx.source.path is not None: identifier = ctx.source.path if identifier is not None: configs.append('this.page.identifier = %s;' % htmlsafe_json_dump(identifier)) if url is None and ctx.source is not None: try: url = url_to(ctx.source, external=True) except RuntimeError: url = None if url is not None: configs.append('this.page.url = %s;' % htmlsafe_json_dump(url)) if title is not None: configs.append('this.page.title = %s;' % htmlsafe_json_dump(title)) if category_id is not None: configs.append('this.page.category_id = %s;' % htmlsafe_json_dump(category_id)) return ' '.join(configs)
def __getitem__(self, name): # If any data of a flowblock is accessed, we record that we need # this dependency. ctx = get_ctx() if ctx is not None: ctx.record_dependency(self.flowblockmodel.filename) return self._data[name]
def limit_dependencies(jinja_env, query): if not isinstance(query, Query): return jinja_env.undefined( "limit_dependencies expected a Query instance, not {!r}".format( query)) # XXX: We cache the query results in the pad's record cache, so # any changes in the query results will not be noticed for the # lifetime of the pad. # # ``Lektor.devserver.BackgroundBuilder`` appears to create # a new pad for every rebuild attempt, and so any changes # in query results should get notice at the next rebuild # when running under ``lektor server``. id_ = serialize_query(query) def creator(): return QueryResults(query, id_) with disable_dependency_recording(): root = query.pad.root virtual_path = f'{VIRTUAL_PATH_PREFIX}/{id_}' results = get_or_create_virtual(root, virtual_path, creator) ctx = get_ctx() if ctx is not None: ctx.record_virtual_dependency(results) return PrecomputedQuery(query.path, query.pad, results.query_result_ids, alt=query.alt)
def __html__(self): ctx = get_ctx() # If we're in a nested render, we disable the rendering here or we # risk a recursion error. if ctx is None or self in ctx.flow_block_render_stack: return Markup.escape(repr(self)) ctx.flow_block_render_stack.append(self) try: try: return self.pad.db.env.render_template( [ "blocks/%s.html" % self._data["_flowblock"], "blocks/default.html", ], pad=self.pad, this=self, alt=self.record.alt, values={"record": self.record}, ) except TemplateNotFound: return Markup("[could not find snippet template]") finally: ctx.flow_block_render_stack.pop()
def _iterate(self): """Low level record iteration.""" # If we iterate over children we also need to track those # dependencies. There are two ways in which we track them. The # first is through the start record of the query. If that does # not work for whatever reason (because it does not exist for # instance). self_record = self.pad.get(self.path) if self_record is not None: self.pad.db.track_record_dependency(self_record) # We also always want to record the path itself as dependency. ctx = get_ctx() if ctx is not None: ctx.record_dependency(self.pad.db.to_fs_path(self.path)) for name, is_attachment in self.pad.db.iter_items(self.path): if not ((is_attachment == self._include_attachments) or (not is_attachment == self._include_pages)): continue record = self._get(name, persist=False) if self._visible_only and not record.is_visible: continue for filter in self._filters or (): if not save_eval(filter, record): break else: yield record
def __html__(self): ctx = get_ctx() # Parse config config = get_plugin(u"graphviz").get_config() img_format = config.get("format", "png") substitutions = { k.replace("substitutions.", ""): v for (k, v) in config.items() if k.startswith("substitutions.") } # Add default styles additional_options = [] if u"style.graph" in config: additional_options.append("-G{}".format(config.get("style.graph"))) if u"style.node" in config: additional_options.append("-N{}".format(config.get("style.node"))) if u"style.edge" in config: additional_options.append("-E{}".format(config.get("style.edge"))) # Get artifact image filename image_filename = self.get_image_filename(ctx.source.url_path, img_format) @ctx.sub_artifact(artifact_name=image_filename, sources=[ctx.source.source_filename]) def generate_image(artifact): with artifact.open("w") as f: substituted_source = Template(self.source).safe_substitute(substitutions) f.write(render_diagram(substituted_source, img_format, additional_options)) return image_filename
def image(self, src, title, text): if self.record is not None: url = url_parse(src) if not url.scheme: src = self.record.url_to('!' + src, base_url=get_ctx().base_url) return mistune.Renderer.image(self, src, title, text)
def build_artifact(self, artifact): ctx = get_ctx() source_out = self.build_state.make_named_temporary('less') map_out = self.build_state.make_named_temporary('less-sourcemap') here = os.path.dirname(self.source.source_filename) exe = self.build_state.config['LESSC_EXECUTABLE'] if exe is None: exe = 'lessc' cmdline = [ exe, '--no-js', '--include-path=%s' % here, '--source-map=%s' % map_out, self.source.source_filename, source_out ] reporter.report_debug_info('lessc cmd line', cmdline) proc = portable_popen(cmdline) if proc.wait() != 0: raise RuntimeError('lessc failed') with open(map_out) as f: for dep in json.load(f).get('sources') or (): ctx.record_dependency(os.path.join(here, dep)) artifact.replace_with_file(source_out) @ctx.sub_artifact(artifact_name=artifact.artifact_name + '.map', sources=[self.source.source_filename]) def build_less_sourcemap_artifact(artifact): artifact.replace_with_file(map_out)
def build_artifact(self, artifact): ctx = get_ctx() feed_source = self.source page = feed_source.parent feed = AtomFeed(title=page.record_label + u' — Pallets Project', feed_url=url_to(feed_source, external=True), url=url_to('/blog', external=True), id=get_id(ctx.env.project.id)) for item in page.children.order_by('-pub_date').limit(10): item_author = item['author'] feed.add( item['title'], text_type(item['body']), xml_base=url_to(item, external=True), url=url_to(item, external=True), content_type='html', id=get_id(u'%s/%s' % (ctx.env.project.id, item['_path'].encode('utf-8'))), author=item_author, updated=datetime(*item['pub_date'].timetuple()[:3])) with artifact.open('wb') as f: f.write(feed.to_string().encode('utf-8'))
def link(self, link, title, text): if self.record is not None: url = url_parse(link) if not url.scheme: link = self.record.url_to('!' + link, base_url=get_ctx().base_url) return mistune.Renderer.link(self, link, title, text)
def gen_js(record): if not record or not hasattr(record, "_js"): return "" ctx = get_ctx() def js_template(name): t = """<script>{%% include "%s" %%}</script>""" % name return ctx.env.jinja_env.from_string(t).render() js = record._js ret = [] for src in js["css"]: js["templates"]["shortcodes/add_css.js"] = True js["embed"][f'API.add_css("{escape(src)}")'] = True # FIXME place this in head # s = f'<link rel="stylesheet" href="{escape(src)}"/>' # ret.append(s) for src, async_ in js["links"].items(): s = f'<script src="{escape(src)}"{" async" if async_ else ""}></script>' ret.append(s) for src in js["templates"]: try: s = js_template(src) except TemplateNotFound: s = f"[shortcode template {src} not found]" ret.append(s) for src in js["embed"]: s = f"<script>{src}</script>" ret.append(s) return Markup("\n".join(ret))
def make_default_tmpl_values(self, pad=None, this=None, values=None, alt=None, template=None): values = dict(values or ()) # If not provided, pick the alt from the provided "this" object. # As there is no mandatory format for it, we make sure that we can # deal with a bad attribute there. if alt is None: if this is not None: alt = getattr(this, 'alt', None) if not isinstance(alt, string_types): alt = None if alt is None: alt = PRIMARY_ALT # This is already a global variable but we can inject it as a # local override if available. if pad is None: ctx = get_ctx() if ctx is not None: pad = ctx.pad if pad is not None: values['site'] = pad if this is not None: values['this'] = this if alt is not None: values['alt'] = alt self.plugin_controller.emit('process-template-context', context=values, template=template) return values
def mode_link(mode): try: ctx = get_ctx() if not ctx: return 'DEVMODE?' pad = ctx.pad record = pad.get('/mode/' + mode) if record: title = record['title'] if title.endswith(')'): title = title[:title.rindex('(')] title = title.lower() if not title: if mode.startswith('p'): title = '?' + mode[1:] else: title = mode else: title = "mode not found: " + mode title = title.strip() return '<a href="{url}">{title}</a>'.format(title=title, url='/mode/' + mode) except Exception as ex: print('failed:', ex) raise
def get_og_items(self, record): plugin_config = self.get_config() model_config = IniFile(record.datamodel.filename) root = get_ctx().pad.root items = { 'site_name': plugin_config.get('global.site_name', self.env.project.name), 'url': url_to(record, external=True), 'title': get_og_title(record, model_config, root), 'type': 'website', } image = get_og_image(record, root) if image is not None: items.update({ 'image': url_to(image, external=True), 'image:width': image.width, 'image:height': image.height, 'image:type': 'image/' + image.format, }) if image.parent is root: items['image:alt'] = 'logo' return items
def __getitem__(self, name): # If any data of a flowblock is accessed, we record that we need # this dependency. ctx = get_ctx() if ctx is not None: ctx.record_dependency(self.flowblockmodel.filename) return self._data[name]
def build_artifact(self, artifact): ctx = get_ctx() feed_source = self.source page = feed_source.parent fg = FeedGenerator() fg.id(get_id(ctx.env.project.id)) fg.title(page.record_label + u" — Pallets Project") fg.link(href=url_to("/blog", external=True)) fg.link(href=url_to(feed_source, external=True), rel="self") for item in page.children.order_by('-pub_date', '-pub_order', 'title').limit(10): fe = fg.add_entry() fe.title(item["title"]) fe.content(text_type(item["body"]), type="html") fe.link(href=url_to(item, external=True)) fe.id( get_id(u"{}/{}".format(ctx.env.project.id, item["_path"].encode("utf-8")))) fe.author(name=item["author"]) updated = datetime(*item["pub_date"].timetuple()[:3]) updated = updated.isoformat() + "Z" if not updated.tzinfo else "" fe.updated(updated) with artifact.open('wb') as f: f.write(fg.atom_str(pretty=True))
def build_artifact(self, artifact): ctx = get_ctx() feed_source = self.source page = feed_source.parent feed = AtomFeed( title=page.record_label + u' — Pallets Project', feed_url=url_to(feed_source, external=True), url=url_to('/blog', external=True), id=get_id(ctx.env.project.id) ) for item in page.children.order_by( '-pub_date', '-pub_order', 'title' ).limit(10): item_author = item['author'] feed.add( item['title'], text_type(item['body']), xml_base=url_to(item, external=True), url=url_to(item, external=True), content_type='html', id=get_id(u'%s/%s' % ( ctx.env.project.id, item['_path'].encode('utf-8'))), author=item_author, updated=datetime(*item['pub_date'].timetuple()[:3])) with artifact.open('wb') as f: f.write(feed.to_string().encode('utf-8'))
def make_default_tmpl_values(self, pad=None, this=None, values=None, alt=None, template=None): values = dict(values or ()) # If not provided, pick the alt from the provided "this" object. # As there is no mandatory format for it, we make sure that we can # deal with a bad attribute there. if alt is None: if this is not None: alt = getattr(this, 'alt', None) if not isinstance(alt, string_types): alt = None if alt is None: alt = PRIMARY_ALT # This is already a global variable but we can inject it as a # local override if available. if pad is None: ctx = get_ctx() if ctx is not None: pad = ctx.pad if pad is not None: values['site'] = pad if this is not None: values['this'] = this if alt is not None: values['alt'] = alt self.plugin_controller.emit('process-template-context', context=values, template=template) return values
def image(self, src, title, text): if self.record is not None: url = url_parse(src) if not url.scheme: src = self.record.url_to('!' + src, base_url=get_ctx().base_url) return mistune.Renderer.image(self, src, title, text)
def importPy(fileName): ctx = get_ctx() filePath = os.getcwd( ) + '/content' + ctx.source.path + '/' + fileName # ЪциРђЇРЎѓ№ИЈ with codecs.open(filePath, 'r', 'utf-8') as pyFile: pyStr = pyFile.read() return HTML(u'<code class="language-python">{}</code>'.format(pyStr))
def link(self, link, title, text): if self.record is not None: url = url_parse(link) if not url.scheme: link = self.record.url_to('!' + link, base_url=get_ctx().base_url) return mistune.Renderer.link(self, link, title, text)
def build_artifact(self, artifact): ctx = get_ctx() feed_source = self.source project_id = ctx.env.project.id feed = make_feed(self.source, project_id) for item in get_items(ctx, feed_source): try: _id = get_id('{0}/{1}'.format( project_id, item['_path'].encode('utf-8'))), with ctx.changed_base_url(item.url_path): feed_item = FeedItem(item, feed_source) feed.add( feed_item.title, feed_item.body, xml_base=feed_item.url, url=feed_item.url, content_type='html', id=_id, author=feed_item.author, updated=feed_item.updated, ) except Exception as exc: reporter.report_generic(exc) with artifact.open('wb') as f: f.write(feed.to_string().encode('utf-8'))
def _load_template(self, name, globals): ctx = get_ctx() try: rv = jinja2.Environment._load_template(self, name, globals) if ctx is not None: filename = rv.filename if PY2 and is_windows: try: filename = filename.decode('utf-8') except UnicodeDecodeError: pass ctx.record_dependency(filename) return rv except jinja2.TemplateSyntaxError as e: if ctx is not None: ctx.record_dependency(e.filename) raise except jinja2.TemplateNotFound as e: if ctx is not None: # If we can't find the template we want to record at what # possible locations the template could exist. This will help # out watcher to pick up templates that will appear in the # future. This assumes the loader is a file system loader. for template_name in e.templates: pieces = split_template_path(template_name) for base in self.loader.searchpath: ctx.record_dependency(os.path.join(base, *pieces)) raise
def build_artifact(self, artifact): ctx = get_ctx() feed_source = self.source blog = feed_source.parent summary = get(blog, feed_source.blog_summary_field) or "" if hasattr(summary, "__html__"): subtitle_type = "html" summary = text_type(summary.__html__()) else: subtitle_type = "text" blog_author = text_type(get(blog, feed_source.blog_author_field) or "") feed = Atom1Feed( title=feed_source.feed_name, subtitle=summary, author_name=blog_author, feed_url=url_to(feed_source, external=True), link=url_to(blog, external=True), feed_guid=get_id(ctx.env.project.id), description=None, ) if feed_source.items: # "feed_source.items" is a string like "site.query('/blog')". expr = Expression(ctx.env, feed_source.items) items = expr.evaluate(ctx.pad) else: items = blog.children if feed_source.item_model: items = items.filter(F._model == feed_source.item_model) order_by = "-" + feed_source.item_date_field items = items.order_by(order_by).limit(int(feed_source.limit)) for item in items: try: item_author_field = feed_source.item_author_field item_author = get(item, item_author_field) or blog_author feed.add_item( title=get_item_title(item, feed_source.item_title_field), description=None, content=get_item_body(item, feed_source.item_body_field), link=url_to(item, external=True), unique_id=get_id( u"%s/%s" % (ctx.env.project.id, item["_path"].encode("utf-8"))), author_name=item_author, updateddate=get_item_updated(item, feed_source.item_date_field), ) except Exception as exc: msg = "%s: %s" % (item["_id"], exc) click.echo(click.style("E", fg="red") + " " + msg) with artifact.open("wb") as f: feed.write(f, "utf-8")
def _iterate(self): """Low level record iteration.""" # If we iterate over children we also need to track those # dependencies. There are two ways in which we track them. The # first is through the start record of the query. If that does # not work for whatever reason (because it does not exist for # instance). self_record = self.pad.get(self.path, alt=self.alt) if self_record is not None: self.pad.db.track_record_dependency(self_record) # We also always want to record the path itself as dependency. ctx = get_ctx() if ctx is not None: ctx.record_dependency(self.pad.db.to_fs_path(self.path)) for name, _, is_attachment in self.pad.db.iter_items( self.path, alt=self.alt): if not ((is_attachment == self._include_attachments) or (not is_attachment == self._include_pages)): continue record = self._get(name, persist=False) if self._matches(record): yield record
def build_artifact(self, artifact): ctx = get_ctx() plugin = ctx.env.plugins["thumbnail-generator"] config = plugin.config artifact.ensure_dir() AttachmentBuildProgram.build_artifact(self, artifact) if not config: return source_img = artifact.source_obj.attachment_filename with open(source_img, "rb") as f: _, w, h = get_image_info(f) # For every section in the config, we need to generate one image. for item, conf in config.items(): width = int(conf["max_width"]) height = int(conf.get("max_height", "0")) if not height: _, height = compute_dimensions(width, None, w, h) df = artifact.source_obj.url_path ext_pos = df.rfind(".") dst_filename = "%s-%s.%s" % (df[:ext_pos], item, df[ext_pos + 1:]) def closure(dst_filename, source_img, width, height, resize_image=True): # We need this closure, otherwise variables get updated and this # doesn't work at all. @ctx.sub_artifact(artifact_name=dst_filename, sources=[source_img]) def build_thumbnail_artifact(artifact): artifact.ensure_dir() if not resize_image: shutil.copy2(source_img, artifact.dst_filename) else: process_image( ctx, source_img, artifact.dst_filename, width, height, quality=85, extra_params=[ "-strip", "-interlace", "Plane", ], ) # If the image is larger than the max_width, resize it, otherwise # just copy it. resize_image = w > width or h > height closure(dst_filename, source_img, width, height, resize_image)
def _load_template(self, name, globals): ctx = get_ctx() try: rv = jinja2.Environment._load_template(self, name, globals) if ctx is not None: filename = rv.filename if PY2 and is_windows: try: filename = filename.decode('utf-8') except UnicodeDecodeError: pass ctx.record_dependency(filename) return rv except jinja2.TemplateSyntaxError as e: if ctx is not None: ctx.record_dependency(e.filename) raise except jinja2.TemplateNotFound as e: if ctx is not None: # If we can't find the template we want to record at what # possible locations the template could exist. This will help # out watcher to pick up templates that will appear in the # future. This assumes the loader is a file system loader. for template_name in e.templates: pieces = split_template_path(template_name) for base in self.loader.searchpath: ctx.record_dependency(os.path.join(base, *pieces)) raise
def drender(match, record): content = match.group('content') align = '' other = '' items = content.split(',') words = items[0].split(' ') name = words[0] if len(words) > 1: align = words[1].strip() if len(items) > 1: other = items[1].strip() # sort out the align style = '' if align in ('left', 'right'): style = 'float: %s;' % align elif align == 'top': style = 'vertial-align: top;' elif align == 'middle': style = 'vertical-align: middle;' # this is not exactly right, but is the best there is elif align == 'bottom': style = 'vertical-align: initial;' # sort out the other params = '' if '=' in other: params = other elif ':' in other: style += ' %s' % other # put it all together if style.strip() != '': params = ('style="%s" %s' % (style.strip(), params.strip())).strip() # sort out the href if '.' not in name: name = '%s.gif' % name href = '/Diagrams/%s' % name # get the alt text try: pad = get_ctx().pad diagram = pad.get(href) alttext = diagram['alttext'] alttext = html.escape(alttext, quote=True) except: print('Error getting alt text for diagram "%s"' % href) traceback.print_exc() alttext = False if alttext: alttag = ' alt="%s"' % alttext else: alttag = '' if params != '': return '<img class="diagram"%s src="%s" %s />' % (alttag, href, params) else: return '<img class="diagram"%s src="%s" />' % (alttag, href)
def get_lektor_config(self): """Returns the global config.""" ctx = get_ctx() if ctx is not None: cfg = ctx.pad.db.config else: cfg = self.env.load_config() return cfg
def get_pygments_stylesheet(artifact_name='/static/pygments.css'): ctx = get_ctx() @ctx.sub_artifact(artifact_name=artifact_name, sources=[ self.config_filename]) def build_stylesheet(artifact): with artifact.open('w') as f: f.write(self.get_formatter().get_style_defs()) return artifact_name
def __init__(self, image, config=None, ctx=None): if config is None: config = self.DEFAULT_CONFIG.copy() if ctx is None: ctx = get_ctx() self.config = config self.image = image self.ctx = ctx
def get_lektor_config(self): """Returns the global config.""" ctx = get_ctx() if ctx is not None: cfg = ctx.pad.db.config else: cfg = self.env.load_config() return cfg
def pythonmarkdown_to_html(text, record=None): """ Convert python-markdown into html. """ ctx = get_ctx() if ctx is None: raise RuntimeError('Context is required for python-markdown rendering') env = get_ctx().env plugin = env.plugins.get('pythonmarkdown', None) if not plugin: raise RuntimeError('PythonMarkdownPLugin is required for python-markdown rendering') cfg = PythonMarkdownConfig(plugin.get_config()) # TODO May need to emit event to let other plugin hook into this one. try: return markdown.markdown(text, **cfg.options) except: return "pythonmarkdown error: " + traceback.format_exc()
def _require_ctx(record): ctx = get_ctx() if ctx is None: raise RuntimeError('This operation requires a context but none was ' 'on the stack.') if ctx.pad is not record.pad: raise RuntimeError('The context on the stack does not match the ' 'pad of the record.') return ctx
def _require_ctx(record): ctx = get_ctx() if ctx is None: raise RuntimeError('This operation requires a context but none was ' 'on the stack.') if ctx.pad is not record.pad: raise RuntimeError('The context on the stack does not match the ' 'pad of the record.') return ctx
def build_artifact(self, artifact): ctx = get_ctx() feed_source = self.source blog = feed_source.parent summary = get(blog, feed_source.blog_summary_field) or '' subtitle_type = ('html' if hasattr(summary, '__html__') else 'text') blog_author = unicode(get(blog, feed_source.blog_author_field) or '') generator = ('Lektor Atom Plugin', 'https://github.com/ajdavis/lektor-atom', pkg_resources.get_distribution('lektor-atom').version) project_id = ctx.env.load_config().base_url if not project_id: project_id = ctx.env.project.id feed = AtomFeed( title=feed_source.feed_name, subtitle=unicode(summary), subtitle_type=subtitle_type, author=blog_author, feed_url=url_to(feed_source, external=True), url=url_to(blog, external=True), id=get_id(project_id), generator=generator) if feed_source.items: # "feed_source.items" is a string like "site.query('/blog')". expr = Expression(ctx.env, feed_source.items) items = expr.evaluate(ctx.pad) else: items = blog.children if feed_source.item_model: items = items.filter(F._model == feed_source.item_model) order_by = '-' + feed_source.item_date_field items = items.order_by(order_by).limit(int(feed_source.limit)) for item in items: item_author_field = feed_source.item_author_field item_author = get(item, item_author_field) or blog_author feed.add( get_item_title(item, feed_source.item_title_field), get_item_body(item, feed_source.item_body_field), xml_base=url_to(item, external=True), url=url_to(item, external=True), content_type='html', id=get_id(u'%s/%s' % ( project_id, item['_path'].encode('utf-8'))), author=item_author, updated=get_item_updated(item, feed_source.item_date_field)) with artifact.open('wb') as f: f.write(feed.to_string().encode('utf-8'))
def init_translator(self): ctx = get_ctx() if not ctx: self.translator = gettext.GNUTranslations() return super().__init__() if not self.__lastlang == ctx.locale: self.__lastlang = ctx.locale self.translator = gettext.translation("contents", join(self.i18npath, '_compiled'), languages=[ctx.locale], fallback=True)
def track_record_dependency(self, record): ctx = get_ctx() if ctx is not None: for filename in record.iter_source_filenames(): ctx.record_dependency(filename) if record.datamodel.filename: ctx.record_dependency(record.datamodel.filename) for dep_model in self.iter_dependent_models(record.datamodel): if dep_model.filename: ctx.record_dependency(dep_model.filename) return record
def link(self, link, title, text): if self.record is not None: url = url_parse(link) if not url.scheme: link = self.record.url_to('!' + link, base_url=get_ctx().base_url) link = escape(link) if not title: return '<a href="%s">%s</a>' % (link, text) title = escape(title) return '<a href="%s" title="%s">%s</a>' % (link, title, text)
def build_artifact(self, artifact): ctx = get_ctx() source = self.source appcast = AppCast( title=source.cast_name, link=url_to(source, external=True), ) try: expr = Expression(ctx.env, source.items) except AttributeError: items = source.parent.children else: items = expr.evaluate(ctx.pad) if source.item_model: items = items.filter(F._model == source.item_model) items = items.order_by('-build_number') for item in items: with ctx.changed_base_url(item.url_path): description = six.text_type(markupsafe.escape(item['note'])) try: offset = int(source.timezone) except ValueError: tzinfo = pytz.timezone(source.timezone) else: tzinfo = pytz.FixedOffset(offset) pub_date = item['pub_datetime'].replace(tzinfo=tzinfo) try: build_number = str(item['build_number']) if '.' in build_number: build_number = build_number.rstrip('0').rstrip('.') appcast.add( title='Version {}'.format(item['version']), description=description, pub_date=pub_date, url=item['download_url'], build=build_number, version=item['version'], length=item['length'], dsasign=item['dsa_signature'], minsysver=item['min_sysver'], ) except Exception as e: msg = '{}: {}'.format(item.id, e) click.echo(click.style('E', fg='red') + ' ' + msg) with artifact.open('wb') as f: f.write(appcast.to_string().encode('utf-8'))
def image(self, src, title, text): if self.record is not None: url = url_parse(src) if not url.scheme: src = self.record.url_to('!' + src, base_url=get_ctx().base_url) src = escape(src) text = escape(text) if title: title = escape(title) return '<img src="%s" alt="%s" title="%s">' % (src, text, title) return '<img src="%s" alt="%s">' % (src, text)
def get_plugin(plugin_id_or_class, env=None): """Looks up the plugin instance by id or class.""" if env is None: ctx = get_ctx() if ctx is None: raise RuntimeError('Context is unavailable and no enviroment ' 'was passed to the function.') env = ctx.env plugin_id = env.plugin_ids_by_class.get(plugin_id_or_class, plugin_id_or_class) try: return env.plugins[plugin_id] except KeyError: raise LookupError('Plugin %r not found' % plugin_id)
def __getitem__(self, name): # If any data of a flowblock is accessed, we record that we need # this dependency. ctx = get_ctx() if ctx is not None: ctx.record_dependency(self.flowblockmodel.filename) rv = self._bound_data.get(name, Ellipsis) if rv is not Ellipsis: return rv rv = self._data[name] if hasattr(rv, '__get__'): rv = rv.__get__(self.record) self._bound_data[name] = rv return rv
def get_config(self, fresh=False): """Returns the config specific for this plugin. By default this will be cached for the current build context but this can be disabled by passing ``fresh=True``. """ ctx = get_ctx() if ctx is not None and not fresh: cache = ctx.cache.setdefault(__name__ + ':configs', {}) cfg = cache.get(self.id) if cfg is None: cfg = IniFile(self.config_filename) cache[self.id] = cfg else: cfg = IniFile(self.config_filename) return cfg
def icon_path(self, license): icon_target_path = ( '/static/lektor-creative-commons/{type}/{version}/{size}.png' ).format(**license) icon_source_path = os.path.join( os.path.dirname(__file__), 'assets', license['type'], license['version'], license['size'] + '.png' ) ctx = get_ctx() @ctx.sub_artifact( icon_target_path, sources=[ctx.source.source_filename], source_obj=icon_source_path ) def copy_icon(artifact): artifact.replace_with_file(artifact.source_obj, copy=True) return icon_target_path
def markdown_to_html(text): ctx = get_ctx() if ctx is None: raise RuntimeError("Context is required for markdown rendering") # These markdown parsers are all terrible. Not one of them does not # modify internal state. So since we only do one of those per thread # we can at least cache them on a thread local. md = getattr(_markdown_cache, "md", None) if md is None: md = make_markdown(ctx.env) _markdown_cache.md = md meta = {} ctx.env.plugin_controller.emit("markdown-meta-init", meta=meta) md.renderer.meta = meta rv = md(text) ctx.env.plugin_controller.emit("markdown-meta-postprocess", meta=meta) return rv, meta
def image(self, src, title, text): if self.record is not None: url = url_parse(src) if not url.scheme: context = get_ctx() attachment = self.record.attachments.get(src) # image is attached to the current record if context.base_url == self.record.url_path and attachment: # this handle situations where the last path contains # a "." and therefor will be build in a image instead of # a directory and the path to the image will be # _last_path.something/image.jpg instead of # last_path/image.jpg src = self.record.url_to(attachment.url_path) else: src = self.record.url_to('!' + src, base_url=context.base_url) return mistune.Renderer.image(self, src, title, text)
def get_bag(self, name): sources = self._known_bags.get(name) if not sources: return None rv = self._bags.get(name) if rv is None: filenames = [] rv = OrderedDict() for filename in sources: filename = os.path.join(self.root_path, filename) rv = merge(rv, load_databag(filename)) filenames.append(filename) self._bags[name] = (rv, filenames) else: rv, filenames = rv ctx = get_ctx() if ctx is not None: for filename in filenames: ctx.record_dependency(filename) return rv
def find_record_for_flowblock(blck): """The record that contains this flow block. This might be unavailable in certain situations, it is however very useful when using the generic block template rendering. """ ctx = get_ctx() if ctx is None: raise RuntimeError('Context unavailable') record = ctx.record if record is None: raise RuntimeError('Context does not point to a record') # It's only the correct record, if we are contained as a field in it. # This could be improved by making a better mapping for this on the # datamodel probably but it's good enough for the moment. for key, value in record.iter_fields(): if isinstance(value, Flow): for other_blck in value.blocks: if other_blck is blck: return record return Undefined('Associated record unavailable.', name='record')