def render(site: Site) -> None: logger = logging.getLogger() site.resources.copytree(join('public', 'static'), site.configuration.www_directory_path) static_environment = create_environment(site) render_tree(site.configuration.www_directory_path, static_environment, site.configuration) sass.render_tree(site.configuration.www_directory_path) for locale, locale_configuration in site.configuration.locales.items(): localized_environment = create_environment(site, locale) if site.configuration.multilingual: www_directory_path = join( site.configuration.www_directory_path, locale_configuration.alias) else: www_directory_path = site.configuration.www_directory_path site.resources.copytree( join('public', 'localized'), www_directory_path) render_tree(www_directory_path, localized_environment, site.configuration) _render_entity_type(www_directory_path, site.ancestry.files.values( ), 'file', site.configuration, locale, localized_environment) logger.info('Rendered %d files in %s.' % (len(site.ancestry.files), locale)) _render_entity_type(www_directory_path, site.ancestry.people.values( ), 'person', site.configuration, locale, localized_environment) logger.info('Rendered %d people in %s.' % (len(site.ancestry.people), locale)) _render_entity_type(www_directory_path, site.ancestry.places.values( ), 'place', site.configuration, locale, localized_environment) logger.info('Rendered %d places in %s.' % (len(site.ancestry.places), locale)) _render_entity_type(www_directory_path, site.ancestry.events.values( ), 'event', site.configuration, locale, localized_environment) logger.info('Rendered %d events in %s.' % (len(site.ancestry.events), locale)) _render_entity_type(www_directory_path, site.ancestry.citations.values( ), 'citation', site.configuration, locale, localized_environment) logger.info('Rendered %d citations in %s.' % (len(site.ancestry.citations), locale)) _render_entity_type(www_directory_path, site.ancestry.sources.values( ), 'source', site.configuration, locale, localized_environment) logger.info('Rendered %d sources in %s.' % (len(site.ancestry.sources), locale)) with Translations(site.translations[locale]): _render_openapi(www_directory_path, site) logger.info('Rendered OpenAPI documentation.') chmod(site.configuration.www_directory_path, 0o755) for directory_path, subdirectory_names, file_names in os.walk(site.configuration.www_directory_path): for subdirectory_name in subdirectory_names: chmod(join(directory_path, subdirectory_name), 0o755) for file_name in file_names: chmod(join(directory_path, file_name), 0o644) site.event_dispatcher.dispatch(PostRenderEvent())
def test_with_unknown_plugin_class(self): with TemporaryDirectory() as www_directory_path: environment = create_environment( Site(Configuration(www_directory_path, 'https://example.com'))) template = '{% if "betty.UnknownPlugin" in plugins %}true{% else %}false{% endif %}' self.assertEquals('false', environment.from_string(template).render())
def render(site: Site) -> None: logger = logging.getLogger() environment = create_environment(site) _render_public(site, environment) _render_entity_type(site, environment, site.ancestry.files.values(), 'file') logger.info('Rendered %d files.' % len(site.ancestry.files)) _render_entity_type(site, environment, site.ancestry.people.values(), 'person') logger.info('Rendered %d people.' % len(site.ancestry.people)) _render_entity_type(site, environment, site.ancestry.places.values(), 'place') logger.info('Rendered %d places.' % len(site.ancestry.places)) _render_entity_type(site, environment, site.ancestry.events.values(), 'event') logger.info('Rendered %d events.' % len(site.ancestry.events)) _render_entity_type(site, environment, site.ancestry.citations.values(), 'citation') logger.info('Rendered %d citations.' % len(site.ancestry.citations)) _render_entity_type(site, environment, site.ancestry.sources.values(), 'source') logger.info('Rendered %d sources.' % len(site.ancestry.sources)) chmod(site.configuration.www_directory_path, 0o755) for directory_path, subdirectory_names, file_names in os.walk( site.configuration.www_directory_path): for subdirectory_name in subdirectory_names: chmod(join(directory_path, subdirectory_name), 0o755) for file_name in file_names: chmod(join(directory_path, file_name), 0o644) site.event_dispatcher.dispatch(PostRenderEvent(environment))
def test(self, expected, template, data): with TemporaryDirectory() as www_directory_path: environment = create_environment( Site(Configuration(www_directory_path, 'https://example.com'))) self.assertEquals( expected, environment.from_string(template).render(data=data))
def test_filter(self, m_expanduser, m_requests): with TemporaryDirectory() as cache_directory_path: m_expanduser.side_effect = lambda _: cache_directory_path with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://ancestry.example.com') configuration.plugins[Wikipedia] = {} environment = create_environment(Site(configuration)) page_uri = 'https://en.wikipedia.org/wiki/Amsterdam' link = Link(page_uri) api_uri = 'https://en.wikipedia.org/w/api.php?action=query&titles=Amsterdam&prop=extracts&exintro&format=json&formatversion=2' title = 'Amstelredam' extract = 'De hoofdstad van Nederland.' api_response_body = { 'query': { 'pages': [ { 'title': title, 'extract': extract, }, ], } } m_requests.register_uri('GET', api_uri, json=api_response_body) actual = environment.from_string( '{% for entry in ([link] | wikipedia) %}{{ entry.content }}{% endfor %}' ).render(link=link) self.assertEquals(extract, actual)
def test_with_disabled_plugin(self): with TemporaryDirectory() as www_directory_path: environment = create_environment( Site(Configuration(www_directory_path, 'https://example.com'))) template = '{% if "' + TestPlugin.__module__ + \ '.TestPlugin" in plugins %}true{% else %}false{% endif %}' self.assertEquals('false', environment.from_string(template).render())
def test(self): with TemporaryDirectory() as www_directory_path: configuration = Configuration(www_directory_path, 'https://example.com') environment = create_environment(Site(configuration)) template = '{{ date | format_date }}' date = Date(1970, 1, 1) self.assertEquals( 'January 1, 1970', environment.from_string(template).render(date=date))
def test_with_empty_iterable(self): with TemporaryDirectory() as www_directory_path: configuration = Configuration(www_directory_path, 'https://example.com') environment = create_environment(Site(configuration)) template = '{{ data | sort_localizeds(localized_attribute="names", sort_attribute="name") }}' data = [] self.assertEquals( '[]', environment.from_string(template).render(data=data))
def test(self, expected, template, file): with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') environment = create_environment(Site(configuration)) actual = environment.from_string(template).render(file=file) self.assertEquals(expected, actual) for file_path in actual.split(':'): self.assertTrue( exists( join(configuration.www_directory_path, file_path[1:])))
def test_empty(self): with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') configuration.locales['en-US'] = LocaleConfiguration('en-US', 'en') configuration.locales['nl-NL'] = LocaleConfiguration('nl-NL', 'nl') site = Site(configuration) environment = create_environment(site) indexed = list(index(site, environment)) self.assertEquals([], indexed)
def _render_config(self) -> None: output_directory_path = os.path.join(self._site.configuration.output_directory_path, 'nginx') makedirs(output_directory_path) # Render the ngnix configuration. file_name = 'nginx.conf.j2' destination_file_path = os.path.join(output_directory_path, file_name) self._site.resources.copy2(file_name, destination_file_path) # Render the Dockerfile. render_file(destination_file_path, create_environment(self._site)) copyfile(os.path.join(DOCKER_PATH, 'Dockerfile'), os.path.join(output_directory_path, 'Dockerfile'))
def test_person_without_names(self): with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') configuration.locales['en-US'] = LocaleConfiguration('en-US', 'en') configuration.locales['nl-NL'] = LocaleConfiguration('nl-NL', 'nl') site = Site(configuration) environment = create_environment(site) person_id = 'P1' person = Person(person_id) site.ancestry.people[person_id] = person indexed = list(index(site, environment)) self.assertEquals([], indexed)
def test_file_without_description(self): with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') configuration.locales['en-US'] = LocaleConfiguration('en-US', 'en') configuration.locales['nl-NL'] = LocaleConfiguration('nl-NL', 'nl') site = Site(configuration) environment = create_environment(site) file_id = 'F1' file = File(file_id, __file__) site.ancestry.files[file_id] = file indexed = list(index(site, environment)) self.assertEquals([], indexed)
def test_person_with_affiliation_name(self, expected: str, locale: str): with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') configuration.locales['en-US'] = LocaleConfiguration('en-US', 'en') configuration.locales['nl-NL'] = LocaleConfiguration('nl-NL', 'nl') site = Site(configuration) environment = create_environment(site, locale) person_id = 'P1' affiliation_name = 'Doughnut' person = Person(person_id) person.names.append(PersonName(None, affiliation_name)) site.ancestry.people[person_id] = person indexed = list(index(site, environment)) self.assertEquals('doughnut', indexed[0]['text']) self.assertIn(expected, indexed[0]['result'])
def test_file(self, expected: str, locale: str): with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') configuration.locales['en-US'] = LocaleConfiguration('en-US', 'en') configuration.locales['nl-NL'] = LocaleConfiguration('nl-NL', 'nl') site = Site(configuration) environment = create_environment(site, locale) file_id = 'F1' file = File(file_id, __file__) file.description = '"file" is Dutch for "traffic jam"' site.ancestry.files[file_id] = file indexed = list(index(site, environment)) self.assertEquals('"file" is dutch for "traffic jam"', indexed[0]['text']) self.assertIn(expected, indexed[0]['result'])
def test_place(self, expected: str, locale: str): with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') configuration.locales['en-US'] = LocaleConfiguration('en-US', 'en') configuration.locales['nl-NL'] = LocaleConfiguration('nl-NL', 'nl') site = Site(configuration) environment = create_environment(site, locale) place_id = 'P1' place = Place(place_id, [ LocalizedName('Netherlands', 'en'), LocalizedName('Nederland', 'nl') ]) site.ancestry.places[place_id] = place indexed = list(index(site, environment)) self.assertEquals('netherlands nederland', indexed[0]['text']) self.assertIn(expected, indexed[0]['result'])
def test(self): with TemporaryDirectory() as www_directory_path: configuration = Configuration(www_directory_path, 'https://example.com') environment = create_environment(Site(configuration)) template = '{{ data | sort_localizeds(localized_attribute="names", sort_attribute="name") }}' data = [ self.WithLocalizedNames('third', [ LocalizedName('3', 'nl-NL'), ]), self.WithLocalizedNames('second', [ LocalizedName('2', 'en'), LocalizedName('1', 'nl-NL'), ]), self.WithLocalizedNames('first', [ LocalizedName('2', 'nl-NL'), LocalizedName('1', 'en-US'), ]), ] self.assertEquals( '[first, second, third]', environment.from_string(template).render(data=data))
def _index(self) -> Iterable: # Create the environment here, because doing so in the initializer would be at a time when not all plugins have # been initialized yet environment = create_environment(self._site) for person in self._site.ancestry.people.values(): yield { 'text': ('%s %s' % (person.individual_name, person.family_name)).lower(), 'result': environment.get_template( 'search-result-person.html.j2').render({ 'person': person, }) } for place in self._site.ancestry.places.values(): yield { 'text': place.name.lower(), 'result': environment.get_template('search-result-place.html.j2').render( { 'place': place, }) }
def _render(self) -> None: js_plugins = list([plugin for plugin in self._site.plugins.values( ) if isinstance(plugin, JsPackageProvider)]) js_plugin_names = [plugin.name() for plugin in js_plugins] build_id = hashlib.md5(':'.join(js_plugin_names).encode()).hexdigest() build_directory_path = path.join( self._site.configuration.cache_directory_path, self.name(), betty_instance_id(), build_id) # Build plugins' JavaScript assets. dependencies = {} environment = create_environment(self._site) for plugin in [self] + js_plugins: plugin_build_directory_path = path.join( build_directory_path, plugin.name()) with _NodeModulesBackup(plugin_build_directory_path): try: shutil.rmtree(plugin_build_directory_path) except FileNotFoundError: pass shutil.copytree(path.join(plugin.resource_directory_path, 'js'), plugin_build_directory_path) render_tree(plugin_build_directory_path, environment) if not isinstance(plugin, self.__class__): dependencies['%s' % plugin.name( )] = 'file:%s' % plugin_build_directory_path with open(path.join(plugin_build_directory_path, 'package.json'), 'r+') as package_json_f: package_json = json.load(package_json_f) package_json['name'] = plugin.name() package_json_f.seek(0) json.dump(package_json, package_json_f) js_plugin_build_directory_path = path.join( build_directory_path, self.name()) # Add dependencies to the JavaScript plugin. with open(path.join(js_plugin_build_directory_path, 'package.json'), 'r+') as package_json_f: package_json = json.load(package_json_f) package_json['dependencies'].update(dependencies) package_json['scripts'] = { 'webpack': 'webpack --config ./webpack.config.js', } package_json_f.seek(0) json.dump(package_json, package_json_f) # Install third-party dependencies. check_call(['npm', 'install', '--production'], cwd=js_plugin_build_directory_path) # Run Webpack. self._site.resources.copy2(path.join(self._site.configuration.www_directory_path, 'betty.css'), path.join( js_plugin_build_directory_path, 'betty.css')) check_call(['npm', 'run', 'webpack'], cwd=js_plugin_build_directory_path) try: shutil.copytree(path.join(build_directory_path, 'output', 'images'), path.join( self._site.configuration.www_directory_path, 'images')) except FileNotFoundError: # There may not be any images. pass shutil.copy2(path.join(build_directory_path, 'output', 'betty.css'), path.join( self._site.configuration.www_directory_path, 'betty.css')) shutil.copy2(path.join(build_directory_path, 'output', 'betty.js'), path.join( self._site.configuration.www_directory_path, 'betty.js'))