def test_with_meta(self): output = """ <p><a class="wiki-lnk" href="/local/wikilink">Wikilink</a> <code>[[wikilink]]</code></p> <p><a class="wiki-lnk" href="/local/path/to/file_name">File name</a></p> <p><a class="wiki-lnk" href="/local/path/to/file_name">File name</a></p> <p><a class="wiki-lnk" href="/local/path/to/file-name">File name</a></p> <p><a class="wiki-lnk" href="/local/path/to/file_name/?a=b&b=c">File name</a></p> <p><a class="wiki-lnk" href="/local/path/to/file_name.html">File name</a></p> <p><a class="wiki-lnk" href="/local/path/to/file_name.html?a=b&b=c">File name</a></p> <p><a class="wiki-lnk" href="https://www.example.com/">www.example.com</a></p> <p><a class="wiki-lnk" href="https://www.example.com/?a=b&b=c">www.example.com</a></p> <p><a class="wiki-lnk" href="https://www.example.com/example-tutorial">Example tutorial</a></p> <p><a class="wiki-lnk" href="https://www.example.com/example-tutorial">Example Tutorial</a></p> <p><img class="wiki-img" src="/local/wikilink.png" /></p> <p><img class="wiki-img" src="/local/path/to/file_name.jpg?a=b&b=c" /></p> <p><img class="wiki-img" src="https://example.jpeg?a=b&b=c" /></p> <p><img class="wiki-img" src="https://www.example.com/example-tutorial.jpeg" /></p> <p><img class="wiki-img" src="https://example.com/example-tutorial.gif" /></p> <p><img alt="better example" class="wiki-img" src="/local/example_tutorial.jpg" /></p> """.strip() md2 = markdown.Markdown( extensions=[WikiLinkPlusExtension(), MetaExtension()]) html = md2.convert(meta_text + "\n\n" + text) # ~ print(html) self.assertEqual(html, output)
class PostProcessor(object): _markdown_extensions = [MathJaxExtension(), MetaExtension()] @staticmethod def create_slug(title): return "-".join([t.lower() for t in title.split()]) @classmethod def construct_url(cls, post): url = url_for("blogging.page_by_id", post_id=post["post_id"], slug=cls.create_slug(post["title"])) return url @classmethod def render_text(cls, post): md = markdown.Markdown(extensions=cls.all_extensions()) post["rendered_text"] = md.convert(post["text"]) post["meta"] = md.Meta @classmethod def process(cls, post, render=True): """ This method takes the post data and renders it :param post: :param render: :return: """ post["slug"] = cls.create_slug(post["title"]) post["editable"] = current_user.get_id() == post["user_id"] post["url"] = cls.construct_url(post) if render: cls.render_text(post) cls.custom_process(post) return @classmethod def custom_process(cls, post): """ Override this method to add additional processes. The result is that the ``post`` dict is modified or enhanced with newer key value pairs. :param post: The post data with values for keys such as title, text, tags etc. :type post: dict """ pass @classmethod def all_extensions(cls): return cls._markdown_extensions @classmethod def set_custom_extensions(cls, extensions): assert type(extensions) == list cls._markdown_extensions.append(cls._custom_extensions)
def render(self, gs): md = Markdown(extensions=[ MetaExtension(), TableExtension(), WikiLinkExtension(), CMS7Extension(gs, baselevel=2), TocExtension() ], output_format='html5') return Markup(md.convert(self.text))
def render(self, gs, *, baselevel=2, hyphenate=False, paragraphs=None): md = Markdown(extensions=[ MetaExtension(), TableExtension(), WikiLinkExtension(), CMS7Extension(gs, path=self.source, baselevel=baselevel, hyphenate=hyphenate, paragraphs=paragraphs), TocExtension(anchorlink=True) ], output_format='html5') return Markup(md.convert(self.text))
class PostProcessor(object): _markdown_extensions = [MathJaxExtension(), MetaExtension()] @staticmethod def create_slug(title): return slugify(title) @classmethod def construct_url(cls, post): url = url_for("blogging.page_by_id", post_id=post["post_id"], slug=cls.create_slug(post["title"])) return url @classmethod def render_text(cls, post): md = markdown.Markdown(extensions=cls.all_extensions()) post["rendered_text"] = md.convert(post["text"]) post["meta"] = md.Meta @classmethod def is_author(cls, post, user): return user.get_id() == '' + str(post['user_id']) @classmethod def process(cls, post, render=True): """ This method takes the post data and renders it :param post: :param render: :return: """ post["slug"] = cls.create_slug(post["title"]) post["editable"] = cls.is_author(post, current_user) post["url"] = cls.construct_url(post) post["priority"] = 0.8 if render: cls.render_text(post) @classmethod def all_extensions(cls): return cls._markdown_extensions @classmethod def set_custom_extensions(cls, extensions): if type(extensions) == list: cls._markdown_extensions.extend(extensions)
def test_with_meta(self): output = """ <p><a class="wikilink" href="/static/wikilink">Wikilink</a> <code>[[wikilink]]</code></p> <p><a class="wikilink" href="/static/wikilink">Wikilink</a> <code>[[Wikilink]]</code></p> <p><a class="wikilink" href="/static/path/to/file_name">File name</a></p> <p><a class="wikilink" href="/static/path/to/file_name">File name</a></p> <p><a class="wikilink" href="/static/path/to/file-name">File name</a></p> <p><a class="wikilink" href="/static/path/to/file_name/?a=b&b=c">File name</a></p> <p><a class="wikilink" href="/static/path/to/file_name.html">File name</a></p> <p><a class="wikilink" href="/static/path/to/file_name.html?a=b&b=c">File name</a></p> <p><a class="wikilink" href="https://www.example.com/">www.example.com</a></p> <p><a class="wikilink" href="https://www.example.com/?a=b&b=c">www.example.com</a></p> <p><a class="wikilink" href="https://www.example.com/example-tutorial">Example tutorial</a></p> <p><a class="wikilink" href="https://www.example.com/example-tutorial">Example Tutorial</a></p> """.strip() md2 = markdown.Markdown( extensions=[WikiLinkPlusExtension(), MetaExtension()]) html = md2.convert(meta_text + "\n\n" + text) # ~ print(html) self.assertEqual(html, output)
checkclock = ReadOnlyCheckclock( Path("~/.config/qtile/checkclock.sqlite").expanduser(), working_days="Mon-Fri" ) ordinal_pattern = re.compile(r"\b([0-9]{1,2})(st|nd|rd|th)\b") md = markdown.Markdown( output_format="html5", extensions=[ FencedCodeExtension(), CodeHiliteExtension(css_class="highlight", guess_lang=False), DefListExtension(), FootnoteExtension(), MetaExtension(), Nl2BrExtension(), SaneListExtension(), TocExtension(), StrikethroughExtension(), TableExtension(), AttrListExtension(), ], ) DOWNLOAD_EXTENSIONS = [".ods", ".odt"] LEXER_MAP = {"pgsql": "sql"} THEME_MODE_KEY = "theme-mode" DEFAULT_THEME_MODE = "light" SERVER_ROOT = Path(os.path.abspath(os.path.dirname(__file__)))
def handleMatch(self, m): node = markdown.util.etree.Element('mathjax') node.text = markdown.util.AtomicString( m.group(2) + m.group(3) + m.group(2)) return node class MathJaxExtension(markdown.Extension): def extendMarkdown(self, md, md_globals): # Needs to come before escape matching because \ is pretty important # in LaTeX md.inlinePatterns.add('mathjax', MathJaxPattern(), '<escape') _markdown_extensions = [MathJaxExtension(), MetaExtension()] def get_locale(): if 'locale' in session: if session['locale'] is not None: return session['locale'] return 'en' def set_locale(): sqlalchemy_utils.i18n.get_locale = get_locale # Get page by id
from flask import redirect, render_template, send_from_directory, url_for from flask_login import UserMixin, LoginManager, login_user, logout_user from flask_blogging import BloggingEngine from flask_blogging.dynamodbstorage import DynamoDBStorage from flask_fileupload.storage.s3storage import S3Storage from flask_fileupload import FlaskFileUpload from markdown.extensions.attr_list import AttrListExtension from markdown.extensions.extra import ExtraExtension from markdown.extensions.meta import MetaExtension extn1 = AttrListExtension() extn3 = ExtraExtension() extn4 = MetaExtension() app = Flask(__name__) app.config["SECRET_KEY"] = "secret" # for WTF-forms and login app.config["BLOGGING_URL_PREFIX"] = "/blog" # app.config["BLOGGING_DISQUS_SITENAME"] = "test" app.config["BLOGGING_SITEURL"] = "http://localhost:8000" app.config["BLOGGING_SITENAME"] = "Jeremy Clewell" # app.config["BLOGGING_TWITTER_USERNAME"] = "******" app.config["FILEUPLOAD_S3_BUCKET"]='jeremyclewell-site' app.config["FILEUPLOAD_PREFIX"] = "/upload" app.config["FILEUPLOAD_ALLOWED_EXTENSIONS"] = ["png", "jpg", "jpeg", "gif"] app.config["BLOGGING_ESCAPE_MARKDOWN"] = False app.config["BLOGGING_GOOGLE_ANALYTICS"] = "UA-15169356-1"
def _build(self, out="", views=None, user_settings_file=""): out = out or self.environment_dist if os.path.abspath(self.environment_src) in os.path.abspath(out): raise OSError("Cannot build site in source directory") if not os.path.exists(self.environment_src): raise OSError("Cannot find source directory") views = views or self.views if os.path.exists(out): if views == self.views: shutil.rmtree(out) os.mkdir(out) else: os.mkdir(out) if user_settings_file: self.load_user_settings(user_settings_file) self.load_db() md = markdown.Markdown( extensions=[MetaExtension()] + self.settings["pages"]["extensions"], extension_configs=self.settings["pages"]["extension_options"]) #copy assets (skip if this is not the top level of the recursive build) if views == self.views: try: assets_folder = os.path.join( self.environment_src, self.settings["environment"]["assets"]) for f in os.listdir(assets_folder): if os.path.isdir(os.path.join(assets_folder, f)): shutil.copytree(os.path.join(assets_folder, f), os.path.join(out, f)) else: shutil.copy(os.path.join(assets_folder, f), out) except OSError: print("Could not copy assets") #reset g self.g = {} tmp_fname = os.path.join(self.environment_src, "templates", "_tmp.html") #create the html pages for view in views: #if there are subviews, we should build those instead if view.get("subviews"): new_out = os.path.join(out, view["route"]) self._build(out=new_out, views=view["subviews"]) continue #else, build the page for this view # create context dict context = dict( [(k, globals()["__builtins__"][k]) for k in self.settings["templates"]["builtins"]], full_route=view["full_route"], route=view["route"], ) context.update(**view.get("context", {})) # query the database context["query"] = self.query_db(view.get("query")) #determine the markdown pages to use for this view page_fnames = view.get("pages") if page_fnames == None: page_fnames = [ "".join(view["full_route"].lstrip("/").split(".")[:-1]) + ".md" ] if page_fnames: page_fnames = [ os.path.join(self.environment_src, self.settings["environment"]["pages"], fname) for fname in _collection(page_fnames) ] else: page_fnames = [] #load the context processor #syntax: "module.submodule:callable" context_processor_name = view.get("context_processor") if context_processor_name: try: # module_name, variable_name = context_processor_name.split(":") module, context_processor = _eval_module_and_object( context_processor_name) except ValueError: raise ValueError( "incorrect syntax for 'context_processor'") else: context_processor = None with codecs.open(os.path.join(out, view["route"]), mode="w", encoding="utf-8") as out_file: try: blocks = BlockTable(view["template"]) blocks_as_context_vars = {} for page_fname in page_fnames: # with open(page_fname, "r") as page_file: with codecs.open(page_fname, mode="r", encoding="utf-8") as page_file: html = md.convert(six.text_type(page_file.read())) html = html.replace("%", "%").replace( "{", "{").replace("}", "}") meta = {} special = {"__store_as__": "block"} for k, v in getattr(md, "Meta", {}).items(): # double-underscore vars are special vars used by gansa if k in ("__block__", "__store_as__"): d = special else: d = meta # v will always be a list, which is probably not what users want # if only one item is specified if len(v) == 1: d[k] = v[0] else: d[k] = v context.update(meta) block_name = special.get( "__block__", self.settings["templates"]["default_block"]) if special["__store_as__"] == "var": blocks_as_context_vars[block_name] =\ blocks_as_context_vars.get(block_name, "") + html elif special["__store_as__"] == "block": blocks.add(block_name, html) context.update(blocks_as_context_vars) with codecs.open(tmp_fname, mode="w", encoding="utf-8") as tmp: tmp.write(blocks.to_template()) template = self.templates.get_template("_tmp.html") # if no markdown page was found, just write context variables to the template except OSError: template = self.templates.get_template(view["template"]) if context_processor: new_context = context_processor(context, dict(view), self) if new_context != None: context = new_context try: stream = template.render(**context) except TypeError: raise TypeError( "context processor must return dict or other mapping") out_file.write(stream) if views == self.views: try: os.remove(tmp_fname) except OSError: pass if views == self.views and self.settings["callbacks"].get( "postrender"): try: _, callback = _eval_module_and_object( self.settings["callbacks"]["postrender"]) except ValueError: raise ValueError("incorrect syntax for 'postrender'") callback(self, {"views": views, "out": out})
class Wiki: DEFAULT_MD_EXTENSIONS = [ FootnoteExtension(), TocExtension(), TableExtension(), MetaExtension(), AutoTitleExtension(), HintedWikiLinkExtension(), SizeEnabledImageExtension() ] @staticmethod def link_to(page): return getattr(page, 'link_to', None) or '/page/' + page def __init__(self, md_extensions=[...]): if md_extensions[-1] is ...: md_extensions = md_extensions[:-1] + self.DEFAULT_MD_EXTENSIONS self.md = markdown.Markdown(extensions=md_extensions) self.title = 'UNSET TITLE' self.logo = '/static/logo.png' self.root_dir_path = None self.rsc_dir_path = None self.titles: Dict[str, Page] = {} # page keys are always in lowercase self.tags: Dict[str, List[Page]] = defaultdict(list) # tag names are always lowercase self.unique_pages: List[Page] = [] def set_root_path(self, path: Path): self.root_dir_path = path self.rsc_dir_path = path / 'rsc' def scan_path(self, clear=False): if clear: self.clear_pages() conf_path = self.root_dir_path / 'config.py' if conf_path.is_file(): exec(conf_path.read_text(), {'wiki': self}) for page_path in self.root_dir_path.glob('[!_]*.md'): try: with page_path.open() as r: page = Page(r.read(), self) except PageLoadError as e: raise PageLoadError('error loading page ' + str(page_path)) from e self.add_page(page) def clear_pages(self): self.titles.clear() self.tags.clear() self.unique_pages.clear() def add_page(self, page: Page): for title in page.titles: p = self.titles.setdefault(title.lower(), page) if p is not page: raise Exception('multiple pages sharing a title ' + title) for t in page.tags: self.tags[t].append(page) self.unique_pages.append(page) def match(self, main, hints): main_terms = split_terms(main) hint_terms = split_terms(hints) for p in self.unique_pages: s = p.score(main_terms, hint_terms) yield p, s def best_match(self, main, hints)->MaxStore: store = MaxStore() main_terms = split_terms(main) hint_terms = split_terms(hints) for p in self.unique_pages: s = p.score(main_terms, hint_terms, cutoff=store.cutoff) store.add(p, s) return store def __getitem__(self, name): name = name.lower() return self.titles.get(name), self.tags.get(name) def __contains__(self, item): return (item in self.titles) or (item in self.tags) @classmethod def from_dir(cls, dir_path): ret = cls() dir_path = Path(dir_path).absolute() if not dir_path.is_dir(): raise ValueError('path id not a directory') ret.set_root_path(dir_path) ret.scan_path() return ret