def expand(url, obj, re=re.compile(r':(\w+)')): """Substitutes/expands URL parameters beginning with a colon. :param url: a URL with zero or more :key words :param obj: a dictionary where we get key from >>> expand('/:year/:slug/', {'year': 2012, 'slug': 'awesome title'}) '/2011/awesome-title/' """ if isinstance(obj, dict): return re.sub(lambda m: str(obj.get(m.group(1), m.group(1))), url) else: return re.sub(lambda m: str(getattr(obj, m.group(1), m.group(1))), url)
def distinguish(value): """Convert :param value: to None, Int, Float, Bool, a List or String. """ if not isinstance(value, string_types): return value if not isinstance(value, string_types): value = str(value) if value in ['None', 'none', '~', 'null']: return None elif re.match(r'^-?\d+$', value): return int(value) elif re.match(r'^-?\d+.\d+$', value): return float(value) elif value in ['True', 'true', 'on']: return True elif value in ['False', 'false', 'off']: return False elif len(value) >= 2 and value[0] == '[' and value[-1] == ']': tokenizer = shlex.shlex((value[1:-1]).encode('utf-8'), posix=True) tokenizer.whitespace = ','.encode('utf-8') tokenizer.whitespace_split = True tokens = [unsafe(val.decode('utf-8').strip()) for val in list(tokenizer)] return [val for val in tokens if val] else: return unsafe(value)
def distinguish(value): """Convert :param value: to None, Int, Float, Bool, a List or String. """ if not isinstance(value, string_types): return value if not isinstance(value, string_types): value = str(value) if value in ['None', 'none', '~', 'null']: return None elif re.match(r'^-?\d+$', value): return int(value) elif re.match(r'^-?\d+.\d+$', value): return float(value) elif value in ['True', 'true', 'on']: return True elif value in ['False', 'false', 'off']: return False elif len(value) >= 2 and value[0] == '[' and value[-1] == ']': tokenizer = shlex.shlex((value[1:-1]).encode('utf-8'), posix=True) tokenizer.whitespace = ','.encode('utf-8') tokenizer.whitespace_split = True tokens = [ unsafe(val.decode('utf-8').strip()) for val in list(tokenizer) ] return [val for val in tokens if val] else: return unsafe(value)
def init(self, conf, env, num_entries=25): super(RssPerTag, self).init(conf, env) self.num_entries = num_entries env.engine.register( 'rfc822', lambda dt: str(format_date_time(total_seconds(dt - epoch)))) self.type = 'rss'
def run(self): while True: func, args, kargs = self.tasks.get() try: func(*args, **kargs) except Exception as e: log.exception('%s: %s' % (e.__class__.__name__, str(e))) self.tasks.task_done()
def __init__(self, chars, patterns, exceptions=''): self.chars = str('[.' + chars + ']') self.tree = {} for pattern in patterns.split(): self._insert_pattern(pattern) self.exceptions = {} for ex in exceptions.split(): # Convert the hyphenated pattern into a point array for use later. self.exceptions[ex.replace('-', '')] = [0] + [int(h == '-') for h in re.split(r"[a-z]", ex)]
def __init__(self, chars, patterns, exceptions=''): self.chars = str('[.' + chars + ']') self.tree = {} for pattern in patterns.split(): self._insert_pattern(pattern) self.exceptions = {} for ex in exceptions.split(): # Convert the hyphenated pattern into a point array for use later. self.exceptions[ex.replace( '-', '')] = [0] + [int(h == '-') for h in re.split(r"[a-z]", ex)]
def joinurl(*args): """Joins multiple urls pieces to one single URL without loosing the root (first element). If the URL ends with a slash, Acrylamid automatically appends ``index.html``. >>> joinurl('/hello/', '/world/') '/hello/world/index.html' """ rv = [str(mem) for mem in args] if rv[-1].endswith('/'): rv.append('index.html') return normpath('/'.join(rv))
def yamlstyle(fileobj): """Open and read content and return metadata and the position where the actual content begins. If ``pyyaml`` is available we use this parser but we provide a dumb fallback parser that can handle simple assigments in YAML. :param fileobj: fileobj, utf-8 encoded """ head = [] i = 0 while True: line = fileobj.readline() i += 1 if i == 1 and not line.startswith('---'): raise AcrylamidException("no meta information in %r found" % fileobj.name) elif i > 1 and not line.startswith('---'): head.append(line) elif i > 1 and line.startswith('---') or not line: break if yaml: try: return i, yaml.load(''.join(head)) except yaml.YAMLError as e: raise AcrylamidException('YAMLError: %s' % str(e)) else: props = {} for j, line in enumerate(head): if line[0] == '#' or not line.strip(): continue try: key, value = [x.strip() for x in line.split(':', 1)] except ValueError: raise AcrylamidException('%s:%i ValueError: %s\n%s' % ( fileobj.name, j, line.strip('\n'), ("Either your YAML is malformed or our naïve parser is to dumb \n" "to read it. Revalidate your YAML or install PyYAML parser with \n" "> easy_install -U pyyaml"))) props[key] = distinguish(value) if 'title' not in props: raise AcrylamidException('No title given in %r' % fileobj.name) return i, props
def __init__(self, obj, style=None, color=None): if isinstance(obj, ANSIString): if style is None: style = obj.style if color is None: color = obj.color obj = obj.obj elif not isinstance(obj, string_types): obj = str(obj) self.obj = obj if style: self.style = style if color: self.color = color
def yamlstyle(fileobj): """Open and read content and return metadata and the position where the actual content begins. If ``pyyaml`` is available we use this parser but we provide a dumb fallback parser that can handle simple assigments in YAML. :param fileobj: fileobj, utf-8 encoded """ head = [] i = 0 while True: line = fileobj.readline(); i += 1 if i == 1 and not line.startswith('---'): raise AcrylamidException("no meta information in %r found" % fileobj.name) elif i > 1 and not line.startswith('---'): head.append(line) elif i > 1 and line.startswith('---') or not line: break if yaml: try: return i, yaml.load(''.join(head)) except yaml.YAMLError as e: raise AcrylamidException('YAMLError: %s' % str(e)) else: props = {} for j, line in enumerate(head): if line[0] == '#' or not line.strip(): continue try: key, value = [x.strip() for x in line.split(':', 1)] except ValueError: raise AcrylamidException('%s:%i ValueError: %s\n%s' % (fileobj.name, j, line.strip('\n'), ("Either your YAML is malformed or our naïve parser is to dumb \n" "to read it. Revalidate your YAML or install PyYAML parser with \n" "> easy_install -U pyyaml"))) props[key] = distinguish(value) if 'title' not in props: raise AcrylamidException('No title given in %r' % fileobj.name) return i, props
def __init__(self, path, conf): self.filename = path self.tzinfo = conf.get('tzinfo', None) self.defaultcopywildcard = conf.get('copy_wildcard', '_[0-9]*.*') with io.open(path, 'r', encoding='utf-8', errors='replace') as fp: peak = lchop(fp.read(512), BOM_UTF8) fp.seek(0) if peak.startswith('---\n'): i, meta = yamlstyle(fp) elif isrest(peak): i, meta = reststyle(fp) elif peak.startswith('% '): i, meta = pandocstyle(fp) else: i, meta = markdownstyle(fp) meta['title'] = str(meta['title']) # YAML can convert 42 to an int meta['category'] = lchop(dirname(path) + '/', conf['content_dir']).split('/') jekyll = r'(?:(.+?)/)?(\d{4}-\d{2}-\d{2})-(.+)' m = re.match('^' + conf['content_dir'] + jekyll + '$', splitext(path)[0]) if m: meta.setdefault('date', m.group(2)) meta.setdefault('slug', m.group(3)) if m.group(1) is not None: meta['category'] = m.group(1).split('/') self.offset = i Reader.__init__(self, conf, meta) path, ext = os.path.splitext(path) self.path = lchop(path, conf['content_dir']) self.extension = ext[1:]
def distinguish(value): """Convert :param value: to None, Int, Bool, a List or String. """ if not isinstance(value, string_types): return value if not isinstance(value, string_types): value = str(value) if value == '': return None elif value.isdigit(): return int(value) elif value.lower() in ['true', 'false']: return True if value.capitalize() == 'True' else False elif value[0] == '[' and value[-1] == ']': tokenizer = shlex.shlex(value[1:-1], posix=True) value = list(takewhile( lambda token: token != tokenizer.eof, (tokenizer.get_token() for _ in repeat(None)))) return [unsafe(val) for val in value if val != ','] else: return unsafe(value)
def __add__(self, other): return str.__add__(str(self), other)
def encode(self, encoding): return str(self).encode(encoding)
def initialize(conf, env): """Initializes Jinja2 environment, prepares locale and configure some minor things. Filter and View are inited with conf and env, a data dict is returned. """ # initialize cache, optional to cache_dir cache.init(conf.get('cache_dir')) env['version'] = type('Version', (str, ), dict(zip( ['major', 'minor'], LooseVersion(dist.version).version[:2])))(dist.version) # crawl through CHANGES.md and stop on breaking changes if history.breaks(env, cache.emptyrun): cache.shutdown() print("Detected version upgrade that might break your configuration. Run") print("Acrylamid a second time to get rid of this message and premature exit.") raise SystemExit # set up templating environment env.engine = import_object(conf['engine'])() env.engine.init(conf['theme'], cache.cache_dir) env.engine.register('safeslug', helpers.safeslug) env.engine.register('tagify', lambda x: x) # try language set in LANG, if set correctly use it try: locale.setlocale(locale.LC_ALL, str(conf.get('lang', ''))) except (locale.Error, TypeError): # try if LANG is an alias try: locale.setlocale(locale.LC_ALL, locale.locale_alias[str(conf.get('lang', '')).lower()]) except (locale.Error, KeyError): # LANG is not an alias, so we use system's default try: locale.setlocale(locale.LC_ALL, '') except locale.Error: pass # hope this makes Travis happy log.info('notice your OS does not support %s, fallback to %s', conf.get('lang', ''), locale.getlocale()[0]) if locale.getlocale()[0] is not None: conf['lang'] = locale.getlocale()[0][:2] else: # getlocale() is (None, None) aka 'C' conf['lang'] = 'en' if 'www_root' not in conf: log.warn('no `www_root` specified, using localhost:8000') conf['www_root'] = 'http://localhost:8000/' # figure out timezone and set offset, more verbose for 2.6 compatibility td = (datetime.now() - datetime.utcnow()) offset = round(total_seconds(td) / 3600.0) conf['tzinfo'] = readers.Timezone(offset) # determine http(s), host and path env['protocol'], env['netloc'], env['path'], x, y = urlsplit(conf['www_root']) # take off the trailing slash for www_root and path conf['www_root'] = conf['www_root'].rstrip('/') env['path'] = env['path'].rstrip('/') if env['path']: conf['output_dir'] = conf['output_dir'] + env['path'] lazy.enable() filters.initialize(conf["filters_dir"][:], conf, env) lazy.disable() # this has weird side effects with jinja2, so disabled after filters views.initialize(conf["views_dir"][:], conf, env) env.views = views.Views(view for view in views.get_views()) entryfmt, pagefmt = '/:year/:slug/', '/:slug/' for view in views.get_views(): if view.name == 'entry': entryfmt = view.path if view.name == 'page': pagefmt = view.path conf.setdefault('entry_permalink', entryfmt) conf.setdefault('page_permalink', pagefmt) # register webassets to theme engine, make webassets available as env.webassets assets.initialize(conf, env) return {'conf': conf, 'env': env}
def __add__(self, other): return str(self) + other
def __radd__(self, other): return other + str(other)
def initialize(conf, env): """Initializes Jinja2 environment, prepares locale and configure some minor things. Filter and View are inited with conf and env, a data dict is returned. """ # initialize cache, optional to cache_dir cache.init(conf.get('cache_dir')) env['version'] = type( 'Version', (str, ), dict(zip(['major', 'minor'], LooseVersion(dist.version).version[:2])))(dist.version) # crawl through CHANGES.md and stop on breaking changes if history.breaks(env, cache.emptyrun): cache.shutdown() print( "Detected version upgrade that might break your configuration. Run" ) print( "Acrylamid a second time to get rid of this message and premature exit." ) raise SystemExit # set up templating environment env.engine = import_object(conf['engine'])(conf['theme'], cache.cache_dir) env.engine.register('safeslug', helpers.safeslug) env.engine.register('tagify', lambda x: x) # try language set in LANG, if set correctly use it try: locale.setlocale(locale.LC_ALL, str(conf.get('lang', ''))) except (locale.Error, TypeError): # try if LANG is an alias try: locale.setlocale( locale.LC_ALL, locale.locale_alias[str(conf.get('lang', '')).lower()]) except (locale.Error, KeyError): # LANG is not an alias, so we use system's default try: locale.setlocale(locale.LC_ALL, '') except locale.Error: pass # hope this makes Travis happy log.info('notice your OS does not support %s, fallback to %s', conf.get('lang', ''), locale.getlocale()[0]) if locale.getlocale()[0] is not None: conf['lang'] = locale.getlocale()[0][:2] else: # getlocale() is (None, None) aka 'C' conf['lang'] = 'en' if 'www_root' not in conf: log.warn('no `www_root` specified, using localhost:8000') conf['www_root'] = 'http://localhost:8000/' # figure out timezone and set offset, more verbose for 2.6 compatibility td = (datetime.now() - datetime.utcnow()) offset = round(total_seconds(td) / 3600.0) conf['tzinfo'] = readers.Timezone(offset) # determine http(s), host and path env['protocol'], env['netloc'], env['path'], x, y = urlsplit( conf['www_root']) # take off the trailing slash for www_root and path conf['www_root'] = conf['www_root'].rstrip('/') env['path'] = env['path'].rstrip('/') if env['path']: conf['output_dir'] = conf['output_dir'] + env['path'] lazy.enable() filters.initialize(conf["filters_dir"][:], conf, env) lazy.disable( ) # this has weird side effects with jinja2, so disabled after filters views.initialize(conf["views_dir"][:], conf, env) env.views = views.Views(view for view in views.get_views()) entryfmt, pagefmt = '/:year/:slug/', '/:slug/' for view in views.get_views(): if view.name == 'entry': entryfmt = view.path if view.name == 'page': pagefmt = view.path conf.setdefault('entry_permalink', entryfmt) conf.setdefault('page_permalink', pagefmt) # register webassets to theme engine, make webassets available as env.webassets assets.initialize(conf, env) return {'conf': conf, 'env': env}