def test_copy(): from flamingo.core.data_model import ContentSet from copy import deepcopy cs1 = ContentSet() cs1.add(a=1) cs2 = deepcopy(cs1) assert cs1[0]['a'] == cs2[0]['a'] assert cs1[0] is not cs2[0]
def test_exclude(): from flamingo.core.data_model import ContentSet cs = ContentSet() for i in range(10): cs.add(a=i) cs = cs.exclude(a=5) assert [i['a'] for i in cs] == [0, 1, 2, 3, 4, 6, 7, 8, 9]
def test_in(): from flamingo.core.data_model import ContentSet cs = ContentSet() for i in range(10): cs.add(a=i) cs = cs.filter(a__in=[4, 5, 8]) assert [i['a'] for i in cs] == [4, 5, 8]
def test_gte(): from flamingo.core.data_model import ContentSet cs = ContentSet() for i in range(10): cs.add(a=i) cs = cs.filter(a__gte=5) assert [i['a'] for i in cs] == [5, 6, 7, 8, 9]
def test_lt(): from flamingo.core.data_model import ContentSet cs = ContentSet() for i in range(10): cs.add(a=i) cs = cs.filter(a__lt=5) assert [i['a'] for i in cs] == [0, 1, 2, 3, 4]
def test_order_by(): from flamingo.core.data_model import ContentSet cs = ContentSet() cs.add(a=4) cs.add(a=3) cs.add(a=5) cs.add(a=1) cs.add(a=2) assert [i['a'] for i in cs] == [4, 3, 5, 1, 2] assert [i['a'] for i in cs.order_by('a')] == [1, 2, 3, 4, 5] assert [i['a'] for i in cs.order_by('-a')] == [5, 4, 3, 2, 1]
def test_iadd(): from flamingo.core.data_model import ContentSet, Content cs = ContentSet() c1 = Content(a=1) c2 = Content(a=2) cs.add(c1) assert c1 in cs assert c2 not in cs cs += c2 assert c1 in cs assert c2 in cs
def add_media(context, content, name): # gen source if name.startswith('/'): source = os.path.join(context.settings.CONTENT_ROOT, name[1:]) else: source = os.path.join( os.path.dirname( os.path.join(context.settings.CONTENT_ROOT, content['path'])), name, ) source = os.path.normpath(source) # gen destination if name.startswith('/'): destination = os.path.join( context.settings.MEDIA_ROOT, name[1:], ) else: destination = os.path.join( context.settings.MEDIA_ROOT, os.path.dirname(content['path']), os.path.basename(name), ) # gen link link = os.path.join( '/media', os.path.relpath(destination, context.settings.MEDIA_ROOT), ) # content['media'] if not content['media']: content['media'] = ContentSet() media_content = Content(source=source, destination=destination, link=link) content['media'].add(media_content) return media_content
def test_values(): from flamingo.core.data_model import ContentSet cs = ContentSet() for i in range(10): cs.add(a=i, b=i + 1, c=i if i % 2 == 0 else None) assert cs.values('a', 'b', 'c') == [ (0, 1, 0), (1, 2, None), (2, 3, 2), (3, 4, None), (4, 5, 4), (5, 6, None), (6, 7, 6), (7, 8, None), (8, 9, 8), (9, 10, None), ] assert cs.values('c') == [0, 2, 4, 6, 8]
def __init__(self, settings, contents=None): super().__init__(settings) self.settings = settings self.contents = contents or ContentSet()
class Context: def __init__(self, settings): self.settings = settings # setup logging self.logger = logging.getLogger('flamingo') self.logger.debug('setting up context') # setup plugins self.plugins = [] plugins = (self.settings.CORE_PLUGINS + self.settings.DEFAULT_PLUGINS + self.settings.PLUGINS) for plugin in plugins: self.logger.debug("setting up plugin '%s' ", plugin) try: plugin_class = acquire(plugin) self.plugins.append(plugin_class()) except Exception: self.logger.error('plugin setup failed', exc_info=True) # setup parser self.parser = FileParser() self.run_plugin_hook('parser_setup') # parse contents self.contents = ContentSet() self.content = None self._media = [] # FIXME: this should be part of Content() for path in self.get_source_paths(): self.logger.debug("reading %s ", path) try: self.content = Content( path=os.path.relpath(path, settings.CONTENT_ROOT)) self.parser.parse(path, self.content) self.run_plugin_hook('content_parsed', self.content) self.contents.add(self.content) except ParsingError as e: self.logger.error('%s: %s', path, e) except Exception: self.logger.error('exception occoured while reading %s', path, exc_info=True) del self.content self.run_plugin_hook('contents_parsed') # setup templating engine templating_engine_class = acquire(settings.TEMPLATING_ENGINE) self.templating_engine = templating_engine_class( settings.THEME_PATHS + settings.CORE_THEME_PATHS) self.run_plugin_hook('templating_engine_setup', self.templating_engine) self.run_plugin_hook('context_setup') def get_source_paths(self): self.logger.debug('searching for content') supported_extensions = self.parser.get_extensions() if self.settings.CONTENT_PATHS: self.logger.debug('using user defined content paths') for path in self.settings.CONTENT_PATHS: path = os.path.join(self.settings.CONTENT_ROOT, path) extension = os.path.splitext(path)[1][1:] if extension not in supported_extensions: self.logger.debug( "skipping '%s'. extension '%s' is not supported", path, extension) continue yield path else: self.logger.debug("searching content recursive in %s", self.settings.CONTENT_ROOT) for root, dirs, files in os.walk(self.settings.CONTENT_ROOT): for name in files: extension = os.path.splitext(name)[1][1:] if extension not in supported_extensions: continue yield os.path.join(root, name) def run_plugin_hook(self, name, *args, **kwargs): self.logger.debug("running plugin hook '%s'", name) for plugin in self.plugins: hook = getattr(plugin, name, None) if not hook: continue self.logger.debug('running %s.%s', plugin.__class__.__name__, name) hook(self, *args, **kwargs) def render(self, content, template_name=''): template_name = template_name or content['template'] template_context = { 'content': content, 'context': self, } return self.templating_engine.render(template_name, template_context) def copy_media(self, filename, content_source_path): # gen source_path if filename.startswith('/'): source_path = os.path.join(self.settings.CONTENT_ROOT, filename[1:]) else: source_path = os.path.join( os.path.dirname( os.path.join(self.settings.CONTENT_ROOT, content_source_path)), filename, ) source_path = os.path.normpath(source_path) # gen destination_path destination_path = os.path.join( self.settings.MEDIA_ROOT, os.path.relpath(source_path, self.settings.CONTENT_ROOT), ) # gen link link = os.path.join( '/media', os.path.relpath(destination_path, self.settings.MEDIA_ROOT), ) # check if media exists if not os.path.exists(source_path): self.logger.critical( "media '%s' does not exist (used as '%s' in '%s')", source_path, filename, content_source_path, ) else: self._media.append(( source_path, destination_path, )) return source_path, destination_path, link def build(self, clean=True): self.run_plugin_hook('pre_build') def makedirs(path): dirname = os.path.dirname(path) if not os.path.exists(dirname): self.logger.debug('mkdir -p %s', dirname) os.makedirs(dirname) # remove previous artifacts if clean and os.path.exists(self.settings.OUTPUT_ROOT): self.logger.debug('rm -rf %s', self.settings.OUTPUT_ROOT) shutil.rmtree(self.settings.OUTPUT_ROOT) # render contents for content in self.contents: output_path = os.path.join(self.settings.OUTPUT_ROOT, content['output']) makedirs(output_path) # render and write content with open(output_path, 'w+') as f: self.logger.debug("writing '%s'...", output_path) if content['template']: output = self.render(content) else: output = content['content'] f.write(output) if self.settings.CONTENT_PATHS: return # copy media for source_path, destination_path in self._media: makedirs(destination_path) self.logger.debug('cp %s %s', source_path, destination_path) shutil.copy(source_path, destination_path) # copy static for static_dir in self.templating_engine.find_static_dirs(): for root, dirs, files in os.walk(static_dir): for f in files: src = os.path.join(root, f) dst = os.path.join( self.settings.STATIC_ROOT, os.path.relpath(root, static_dir), f, ) self.logger.debug('cp %s %s', src, dst) makedirs(dst) shutil.copy(src, dst) self.run_plugin_hook('post_build')
def __init__(self, settings): self.settings = settings # setup logging self.logger = logging.getLogger('flamingo') self.logger.debug('setting up context') # setup plugins self.plugins = [] plugins = (self.settings.CORE_PLUGINS + self.settings.DEFAULT_PLUGINS + self.settings.PLUGINS) for plugin in plugins: self.logger.debug("setting up plugin '%s' ", plugin) try: plugin_class = acquire(plugin) self.plugins.append(plugin_class()) except Exception: self.logger.error('plugin setup failed', exc_info=True) # setup parser self.parser = FileParser() self.run_plugin_hook('parser_setup') # parse contents self.contents = ContentSet() self.content = None self._media = [] # FIXME: this should be part of Content() for path in self.get_source_paths(): self.logger.debug("reading %s ", path) try: self.content = Content( path=os.path.relpath(path, settings.CONTENT_ROOT)) self.parser.parse(path, self.content) self.run_plugin_hook('content_parsed', self.content) self.contents.add(self.content) except ParsingError as e: self.logger.error('%s: %s', path, e) except Exception: self.logger.error('exception occoured while reading %s', path, exc_info=True) del self.content self.run_plugin_hook('contents_parsed') # setup templating engine templating_engine_class = acquire(settings.TEMPLATING_ENGINE) self.templating_engine = templating_engine_class( settings.THEME_PATHS + settings.CORE_THEME_PATHS) self.run_plugin_hook('templating_engine_setup', self.templating_engine) self.run_plugin_hook('context_setup')
def test_filter(): from flamingo.core.data_model import ContentSet # keyword args cs = ContentSet() for i in range(10): cs.add(a=i) cs = cs.filter(a=5) assert cs.count() == 1 assert cs[0]['a'] == 5 # dict cs = ContentSet() for i in range(10): cs.add(a=i) cs = cs.filter({'a': 5}) assert cs.count() == 1 assert cs[0]['a'] == 5
def test_ContentSet_get(): from flamingo.core.data_model import ContentSet from flamingo.core.errors import ( MultipleObjectsReturned, ObjectDoesNotExist, ) # single object cs = ContentSet() cs.add(a=1) assert cs.get()['a'] == 1 # simple get cs = ContentSet() cs.add(a=1) cs.add(a=2) assert cs.get(a=1)['a'] == 1 # MultipleObjectsReturned cs = ContentSet() cs.add(a=1) cs.add(a=1) with pytest.raises(MultipleObjectsReturned): assert cs.get() with pytest.raises(MultipleObjectsReturned): assert cs.get(a=1) # ObjectDoesNotExist cs = ContentSet() cs.add(a=1) cs.add(a=2) with pytest.raises(ObjectDoesNotExist): assert cs.get(a=3)
def __init__(self, settings, contents=None): super().__init__() self.settings = settings self.errors = [] # setup logging self.logger = logging.getLogger('flamingo') self.logger.debug('setting up context') # setup plugins self.plugins = [] self.plugin_paths = [] plugins = (self.settings.CORE_PLUGINS_PRE + self.settings.DEFAULT_PLUGINS + self.settings.PLUGINS + self.settings.CORE_PLUGINS_POST) for plugin in plugins: self.logger.debug("setting up plugin '%s' ", plugin) try: plugin_class, plugin_path = acquire(plugin) if plugin == 'flamingo.core.plugins.Hooks': self.plugins.append(plugin_class(self)) else: self.plugins.append(plugin_class()) self.plugin_paths.append(plugin_path) except Exception as e: self.logger.error('plugin setup failed', exc_info=True) self.errors.append(e) self.plugin_paths = list(set(self.plugin_paths)) # discover plugin hooks self._plugin_hooks = { 'parser_setup': [], 'content_parsed': [], 'contents_parsed': [], 'templating_engine_setup': [], 'context_setup': [], 'pre_build': [], 'post_build': [], # live-server hooks 'render_content': [], 'render_media_content': [], } hook_names = self._plugin_hooks.keys() for plugin in self.plugins: for hook_name in hook_names: if hook_name not in dir(plugin): continue hook = getattr(plugin, hook_name) if hook: self._plugin_hooks[hook_name].append(( plugin.__class__.__name__, hook, )) # setup parser self.parser = FileParser(context=self) self.run_plugin_hook('parser_setup') # parse contents self.contents = contents or ContentSet() self.parse_all() # setup templating engine templating_engine_class, path = acquire(settings.TEMPLATING_ENGINE) self.templating_engine = templating_engine_class( settings.THEME_PATHS + sum([getattr(i, 'THEME_PATHS', []) for i in self.plugins], []) + settings.CORE_THEME_PATHS) self.run_plugin_hook('templating_engine_setup', self.templating_engine) self.run_plugin_hook('context_setup')