def _populate(self, trans, group): """ Turn the given group information from DB into a dict and add other characteristics like members and repositories. """ model = trans.app.model group_dict = group.to_dict(view='collection', value_mapper=self.__get_value_mapper(trans)) group_members = [] group_repos = [] total_downloads = 0 for uga in group.users: user = trans.sa_session.query(model.User).filter(model.User.table.c.id == uga.user_id).one() user_repos_count = 0 for repo in trans.sa_session.query(model.Repository) \ .filter(model.Repository.table.c.user_id == uga.user_id) \ .join(model.RepositoryMetadata.table) \ .join(model.User.table) \ .outerjoin(model.RepositoryCategoryAssociation.table) \ .outerjoin(model.Category.table): categories = [] for rca in repo.categories: cat_dict = dict(name=rca.category.name, id=trans.app.security.encode_id(rca.category.id)) categories.append(cat_dict) time_repo_created_full = repo.create_time.strftime("%Y-%m-%d %I:%M %p") time_repo_updated_full = repo.update_time.strftime("%Y-%m-%d %I:%M %p") time_repo_created = pretty_print_time_interval(repo.create_time, True) time_repo_updated = pretty_print_time_interval(repo.update_time, True) approved = '' ratings = [] for review in repo.reviews: if review.rating: ratings.append(review.rating) if review.approved == 'yes': approved = 'yes' # TODO add user ratings ratings_mean = str(float(sum(ratings)) / len(ratings)) if len(ratings) > 0 else '' total_downloads += repo.times_downloaded group_repos.append({'name': repo.name, 'times_downloaded': repo.times_downloaded, 'owner': repo.user.username, 'time_created_full': time_repo_created_full, 'time_created': time_repo_created, 'time_updated_full': time_repo_updated_full, 'time_updated': time_repo_updated, 'description': repo.description, 'approved': approved, 'ratings_mean': ratings_mean, 'categories' : categories}) user_repos_count += 1 encoded_user_id = trans.app.security.encode_id(repo.user.id) user_repos_url = web.url_for(controller='repository', action='browse_repositories_by_user', user_id=encoded_user_id) time_created = pretty_print_time_interval(user.create_time, True) member_dict = {'id': encoded_user_id, 'username': user.username, 'user_repos_url': user_repos_url, 'user_repos_count': user_repos_count, 'user_tools_count': 'unknown', 'time_created': time_created} group_members.append(member_dict) group_dict['members'] = group_members group_dict['total_members'] = len(group_members) group_dict['repositories'] = group_repos group_dict['total_repos'] = len(group_repos) group_dict['total_downloads'] = total_downloads return group_dict
def _populate(self, trans, group): """ Turn the given group information from DB into a dict and add other characteristics like members and repositories. """ model = trans.app.model group_dict = group.to_dict(view='collection', value_mapper=self.__get_value_mapper(trans)) group_members = [] group_repos = [] total_downloads = 0 for uga in group.users: user = trans.sa_session.query(model.User).filter(model.User.table.c.id == uga.user_id).one() user_repos_count = 0 for repo in trans.sa_session.query(model.Repository) \ .filter(model.Repository.table.c.user_id == uga.user_id) \ .join(model.RepositoryMetadata.table) \ .join(model.User.table) \ .outerjoin(model.RepositoryCategoryAssociation.table) \ .outerjoin(model.Category.table): categories = [] for rca in repo.categories: cat_dict = dict(name=rca.category.name, id=trans.app.security.encode_id(rca.category.id)) categories.append(cat_dict) time_repo_created_full = repo.create_time.strftime("%Y-%m-%d %I:%M %p") time_repo_updated_full = repo.update_time.strftime("%Y-%m-%d %I:%M %p") time_repo_created = pretty_print_time_interval(repo.create_time, True) time_repo_updated = pretty_print_time_interval(repo.update_time, True) approved = '' ratings = [] for review in repo.reviews: if review.rating: ratings.append(review.rating) if review.approved == 'yes': approved = 'yes' # TODO add user ratings ratings_mean = str(float(sum(ratings)) / len(ratings)) if len(ratings) > 0 else '' total_downloads += repo.times_downloaded group_repos.append({'name': repo.name, 'times_downloaded': repo.times_downloaded, 'owner': repo.user.username, 'time_created_full': time_repo_created_full, 'time_created': time_repo_created, 'time_updated_full': time_repo_updated_full, 'time_updated': time_repo_updated, 'description': repo.description, 'approved': approved, 'ratings_mean': ratings_mean, 'categories' : categories}) user_repos_count += 1 encoded_user_id = trans.app.security.encode_id(repo.user.id) user_repos_url = web.url_for(controller='repository', action='browse_repositories_by_user', user_id=encoded_user_id) time_created = pretty_print_time_interval(user.create_time, True) member_dict = {'id': encoded_user_id, 'username': user.username, 'user_repos_url': user_repos_url, 'user_repos_count': user_repos_count, 'user_tools_count': 'unknown', 'time_created': time_created} group_members.append(member_dict) group_dict['members'] = group_members group_dict['total_members'] = len(group_members) group_dict['repositories'] = group_repos group_dict['total_repos'] = len(group_repos) group_dict['total_downloads'] = total_downloads return group_dict
def get_repos(sa_session): for repo in sa_session.query(model.Repository).filter_by( deleted=False).filter_by(deprecated=False).filter( model.Repository.type != 'tool_dependency_definition'): id = repo.id name = repo.name description = repo.description long_description = repo.long_description homepage_url = repo.homepage_url remote_repository_url = repo.remote_repository_url times_downloaded = repo.times_downloaded if not isinstance(times_downloaded, (int, long)): times_downloaded = 0 repo_owner_username = '' if repo.user_id is not None: user = sa_session.query( model.User).filter(model.User.id == repo.user_id).one() repo_owner_username = user.username approved = 'no' for review in repo.reviews: if review.approved == 'yes': approved = 'yes' break # Format the time since last update to be nicely readable. last_updated = pretty_print_time_interval(repo.update_time) full_last_updated = repo.update_time.strftime("%Y-%m-%d %I:%M %p") yield (id, name, description, long_description, homepage_url, remote_repository_url, repo_owner_username, times_downloaded, approved, last_updated, full_last_updated)
def current_state_time(self): # Docker API returns a stamp w/ higher second precision than Python takes try: stamp = self.inspect['Status']['Timestamp'] except TypeError: return None return pretty_print_time_interval(time=stamp[:stamp.index('.') + 7], precise=True, utc=stamp[-1] == 'Z')
def current_state_time(self): # Docker API returns a stamp w/ higher second precision than Python takes try: stamp = self.inspect['Status']['Timestamp'] except TypeError: return None return pretty_print_time_interval(time=stamp[:stamp.index('.') + 7], precise=True, utc=stamp[-1] == 'Z')
def get_library_dict(self, trans, library, restricted_library_ids=None): """ Return library data in the form of a dictionary. :param library: library :type library: galaxy.model.Library :param restricted_library_ids: ids of restricted libraries to speed up the detection of public libraries :type restricted_library_ids: list of ints :returns: dict with data about the library :rtype: dictionary """ library_dict = library.to_dict(view='element', value_mapper={'id': trans.security.encode_id, 'root_folder_id': trans.security.encode_id}) if restricted_library_ids and library.id in restricted_library_ids: library_dict['public'] = False else: library_dict['public'] = True library_dict['create_time_pretty'] = pretty_print_time_interval(library.create_time, precise=True) if not trans.user_is_admin(): current_user_roles = trans.get_current_user_roles() library_dict['can_user_add'] = trans.app.security_agent.can_add_library_item(current_user_roles, library) library_dict['can_user_modify'] = trans.app.security_agent.can_modify_library_item(current_user_roles, library) library_dict['can_user_manage'] = trans.app.security_agent.can_manage_library_item(current_user_roles, library) else: library_dict['can_user_add'] = True library_dict['can_user_modify'] = True library_dict['can_user_manage'] = True return library_dict
def get_repos( sa_session, path_to_repositories ): """ Load repos from DB and included tools from .xml configs. """ results = [] for repo in sa_session.query( model.Repository ).filter_by( deleted=False ).filter_by( deprecated=False ).filter( model.Repository.type != 'tool_dependency_definition' ): repo_id = repo.id name = repo.name description = repo.description long_description = repo.long_description homepage_url = repo.homepage_url remote_repository_url = repo.remote_repository_url times_downloaded = repo.times_downloaded if not isinstance( times_downloaded, ( int, long ) ): times_downloaded = 0 repo_owner_username = '' if repo.user_id is not None: user = sa_session.query( model.User ).filter( model.User.id == repo.user_id ).one() repo_owner_username = user.username approved = 'no' for review in repo.reviews: if review.approved == 'yes': approved = 'yes' break # Format the time since last update to be nicely readable. last_updated = pretty_print_time_interval( repo.update_time ) full_last_updated = repo.update_time.strftime( "%Y-%m-%d %I:%M %p" ) # Parse all the tools within repo for separate index. tools_list = [] path = os.path.join( path_to_repositories, *model.directory_hash_id( repo.id )) path = os.path.join( path, "repo_%d" % repo.id ) if os.path.exists(path): tools_list.extend( load_one_dir( path ) ) for root, dirs, files in os.walk( path ): if '.hg' in dirs: dirs.remove('.hg') for dirname in dirs: tools_in_dir = load_one_dir( os.path.join( root, dirname ) ) tools_list.extend( tools_in_dir ) results.append(dict( id=repo_id, name=name, description=description, long_description=long_description, homepage_url=homepage_url, remote_repository_url=remote_repository_url, repo_owner_username=repo_owner_username, times_downloaded=times_downloaded, approved=approved, last_updated=last_updated, full_last_updated=full_last_updated, tools_list=tools_list ) ) return results
def get_library_dict(self, trans, library, restricted_library_ids=None): """ Return library data in the form of a dictionary. :param library: library :type library: galaxy.model.Library :param restricted_library_ids: ids of restricted libraries to speed up the detection of public libraries :type restricted_library_ids: list of ints :returns: dict with data about the library :rtype: dictionary """ library_dict = library.to_dict(view='element', value_mapper={ 'id': trans.security.encode_id, 'root_folder_id': trans.security.encode_id }) if restricted_library_ids and library.id in restricted_library_ids: library_dict['public'] = False else: library_dict['public'] = True library_dict['create_time_pretty'] = pretty_print_time_interval( library.create_time, precise=True) if not trans.user_is_admin(): current_user_roles = trans.get_current_user_roles() library_dict[ 'can_user_add'] = trans.app.security_agent.can_add_library_item( current_user_roles, library) library_dict[ 'can_user_modify'] = trans.app.security_agent.can_modify_library_item( current_user_roles, library) library_dict[ 'can_user_manage'] = trans.app.security_agent.can_manage_library_item( current_user_roles, library) else: library_dict['can_user_add'] = True library_dict['can_user_modify'] = True library_dict['can_user_manage'] = True return library_dict
def get_repos( sa_session ): for repo in sa_session.query( model.Repository ).filter_by( deleted=False ).filter_by( deprecated=False ).filter( model.Repository.type != 'tool_dependency_definition' ): id = repo.id name = repo.name description = repo.description long_description = repo.long_description homepage_url = repo.homepage_url remote_repository_url = repo.remote_repository_url times_downloaded = repo.times_downloaded if not isinstance( times_downloaded, ( int, long ) ): times_downloaded = 0 repo_owner_username = '' if repo.user_id is not None: user = sa_session.query( model.User ).filter( model.User.id == repo.user_id ).one() repo_owner_username = user.username approved = 'no' for review in repo.reviews: if review.approved == 'yes': approved = 'yes' break # Format the time since last update to be nicely readable. last_updated = pretty_print_time_interval( repo.update_time ) full_last_updated = repo.update_time.strftime( "%Y-%m-%d %I:%M %p" ) yield ( id, name, description, long_description, homepage_url, remote_repository_url, repo_owner_username, times_downloaded, approved, last_updated, full_last_updated )
def get_library_dict(self, trans, library, prefetched_ids=None): """ Return library data in the form of a dictionary. :param library: library :type library: galaxy.model.Library :param prefetched_ids: dict of 3 sets with available actions for user's accessible libraries and a set of ids of all public libraries. These are used for limiting the number of queries when dictifying a set of libraries. :type prefetched_ids: dict :returns: dict with data about the library :rtype: dictionary """ restricted_library_ids = prefetched_ids.get('restricted_library_ids', None) if prefetched_ids else None allowed_library_add_ids = prefetched_ids.get('allowed_library_add_ids', None) if prefetched_ids else None allowed_library_modify_ids = prefetched_ids.get('allowed_library_modify_ids', None) if prefetched_ids else None allowed_library_manage_ids = prefetched_ids.get('allowed_library_manage_ids', None) if prefetched_ids else None library_dict = library.to_dict(view='element', value_mapper={'id': trans.security.encode_id, 'root_folder_id': trans.security.encode_id}) library_dict['public'] = False if (restricted_library_ids and library.id in restricted_library_ids) else True library_dict['create_time_pretty'] = pretty_print_time_interval(library.create_time, precise=True) if not trans.user_is_admin(): if prefetched_ids: library_dict['can_user_add'] = True if (allowed_library_add_ids and library.id in allowed_library_add_ids) else False library_dict['can_user_modify'] = True if (allowed_library_modify_ids and library.id in allowed_library_modify_ids) else False library_dict['can_user_manage'] = True if (allowed_library_manage_ids and library.id in allowed_library_manage_ids) else False else: current_user_roles = trans.get_current_user_roles() library_dict['can_user_add'] = trans.app.security_agent.can_add_library_item(current_user_roles, library) library_dict['can_user_modify'] = trans.app.security_agent.can_modify_library_item(current_user_roles, library) library_dict['can_user_manage'] = trans.app.security_agent.can_manage_library_item(current_user_roles, library) else: library_dict['can_user_add'] = True library_dict['can_user_modify'] = True library_dict['can_user_manage'] = True return library_dict
def get_library_dict(self, trans, library): """ Return library data in the form of a dictionary. :param library: library :type library: galaxy.model.Library :returns: dict with data about the library :rtype: dictionary """ library_dict = library.to_dict(view='element', value_mapper={ 'id': trans.security.encode_id, 'root_folder_id': trans.security.encode_id }) if trans.app.security_agent.library_is_public(library, contents=False): library_dict['public'] = True library_dict['create_time_pretty'] = pretty_print_time_interval( library.create_time, precise=True) current_user_roles = trans.get_current_user_roles() if not trans.user_is_admin(): library_dict[ 'can_user_add'] = trans.app.security_agent.can_add_library_item( current_user_roles, library) library_dict[ 'can_user_modify'] = trans.app.security_agent.can_modify_library_item( current_user_roles, library) library_dict[ 'can_user_manage'] = trans.app.security_agent.can_manage_library_item( current_user_roles, library) else: library_dict['can_user_add'] = True library_dict['can_user_modify'] = True library_dict['can_user_manage'] = True return library_dict
def get_library_dict( self, trans, library ): """ Return library data in the form of a dictionary. :param library: library :type library: Library :returns: dict with data about the library :rtype: dictionary """ library_dict = library.to_dict( view='element', value_mapper={ 'id': trans.security.encode_id, 'root_folder_id': trans.security.encode_id } ) if trans.app.security_agent.library_is_public( library, contents=False ): library_dict[ 'public' ] = True library_dict[ 'create_time_pretty'] = pretty_print_time_interval( library_dict[ 'create_time' ], precise=True ) current_user_roles = trans.get_current_user_roles() if not trans.user_is_admin(): library_dict[ 'can_user_add' ] = trans.app.security_agent.can_add_library_item( current_user_roles, library ) library_dict[ 'can_user_modify' ] = trans.app.security_agent.can_modify_library_item( current_user_roles, library ) library_dict[ 'can_user_manage' ] = trans.app.security_agent.can_manage_library_item( current_user_roles, library ) else: library_dict[ 'can_user_add' ] = True library_dict[ 'can_user_modify' ] = True library_dict[ 'can_user_manage' ] = True return library_dict
def get_repos(sa_session, path_to_repositories): """ Load repos from DB and included tools from .xml configs. """ results = [] for repo in sa_session.query(model.Repository).filter_by( deleted=False).filter_by(deprecated=False).filter( model.Repository.type != 'tool_dependency_definition'): repo_id = repo.id name = repo.name description = repo.description long_description = repo.long_description homepage_url = repo.homepage_url remote_repository_url = repo.remote_repository_url times_downloaded = repo.times_downloaded if not isinstance(times_downloaded, (int, long)): times_downloaded = 0 repo_owner_username = '' if repo.user_id is not None: user = sa_session.query( model.User).filter(model.User.id == repo.user_id).one() repo_owner_username = user.username approved = 'no' for review in repo.reviews: if review.approved == 'yes': approved = 'yes' break # Format the time since last update to be nicely readable. last_updated = pretty_print_time_interval(repo.update_time) full_last_updated = repo.update_time.strftime("%Y-%m-%d %I:%M %p") # Parse all the tools within repo for separate index. tools_list = [] path = os.path.join(path_to_repositories, *model.directory_hash_id(repo.id)) path = os.path.join(path, "repo_%d" % repo.id) if os.path.exists(path): tools_list.extend(load_one_dir(path)) for root, dirs, files in os.walk(path): if '.hg' in dirs: dirs.remove('.hg') for dirname in dirs: tools_in_dir = load_one_dir(os.path.join(root, dirname)) tools_list.extend(tools_in_dir) results.append( dict(id=repo_id, name=name, description=description, long_description=long_description, homepage_url=homepage_url, remote_repository_url=remote_repository_url, repo_owner_username=repo_owner_username, times_downloaded=times_downloaded, approved=approved, last_updated=last_updated, full_last_updated=full_last_updated, tools_list=tools_list)) return results
def get_repos( sa_session, path_to_repositories ): """ Load repos from DB and included tools from .xml configs. """ results = [] for repo in sa_session.query( model.Repository ).filter_by( deleted=False ).filter_by( deprecated=False ).filter( model.Repository.type != 'tool_dependency_definition' ): repo_id = repo.id name = repo.name description = repo.description long_description = repo.long_description homepage_url = repo.homepage_url remote_repository_url = repo.remote_repository_url times_downloaded = repo.times_downloaded if not isinstance( times_downloaded, ( int, long ) ): times_downloaded = 0 repo_owner_username = '' if repo.user_id is not None: user = sa_session.query( model.User ).filter( model.User.id == repo.user_id ).one() repo_owner_username = user.username approved = 'no' for review in repo.reviews: if review.approved == 'yes': approved = 'yes' break # Format the time since last update to be nicely readable. last_updated = pretty_print_time_interval( repo.update_time ) full_last_updated = repo.update_time.strftime( "%Y-%m-%d %I:%M %p" ) # Parse all the tools within repo for separate index. tools_list = [] path = os.path.join( path_to_repositories, *model.directory_hash_id( repo.id )) path = os.path.join( path, "repo_%d" % repo.id ) if os.path.exists(path): tool_elems = load_tool_elements_from_path(path) if tool_elems: for elem in tool_elems: root = elem[1].getroot() if root.tag == 'tool': tool = {} if root.find('help') is not None: tool.update( dict( help=root.find( 'help' ).text ) ) if root.find('description') is not None: tool.update( dict( description=root.find( 'description' ).text ) ) tool.update( dict( id=root.attrib.get('id'), name=root.attrib.get('name'), version=root.attrib.get('version') ) ) tools_list.append( tool ) results.append(dict( id=repo_id, name=name, description=description, long_description=long_description, homepage_url=homepage_url, remote_repository_url=remote_repository_url, repo_owner_username=repo_owner_username, times_downloaded=times_downloaded, approved=approved, last_updated=last_updated, full_last_updated=full_last_updated, tools_list=tools_list ) ) return results
def get_repos(sa_session, path_to_repositories, hgweb_config_dir): """ Load repos from DB and included tools from .xml configs. """ hgwcm = HgWebConfigManager() hgwcm.hgweb_config_dir = hgweb_config_dir results = [] for repo in sa_session.query(model.Repository).filter_by( deleted=False).filter_by(deprecated=False).filter( model.Repository.type != 'tool_dependency_definition'): category_names = [] for rca in sa_session.query( model.RepositoryCategoryAssociation ).filter(model.RepositoryCategoryAssociation.repository_id == repo.id): for category in sa_session.query(model.Category).filter( model.Category.id == rca.category.id): category_names.append(category.name.lower()) categories = (",").join(category_names) repo_id = repo.id name = repo.name description = repo.description long_description = repo.long_description homepage_url = repo.homepage_url remote_repository_url = repo.remote_repository_url times_downloaded = repo.times_downloaded if not isinstance(times_downloaded, (int, long)): times_downloaded = 0 repo_owner_username = '' if repo.user_id is not None: user = sa_session.query( model.User).filter(model.User.id == repo.user_id).one() repo_owner_username = user.username.lower() approved = 'no' for review in repo.reviews: if review.approved == 'yes': approved = 'yes' break # Format the time since last update to be nicely readable. last_updated = pretty_print_time_interval(repo.update_time) full_last_updated = repo.update_time.strftime("%Y-%m-%d %I:%M %p") # load all changesets of the repo repo_path = hgwcm.get_entry( os.path.join("repos", repo.user.username, repo.name)) hg_repo = hg.repository(ui.ui(), repo_path) lineage = [] for changeset in hg_repo.changelog: lineage.append( str(changeset) + ":" + str(hg_repo.changectx(changeset))) repo_lineage = str(lineage) # Parse all the tools within repo for separate index. tools_list = [] path = os.path.join(path_to_repositories, *directory_hash_id(repo.id)) path = os.path.join(path, "repo_%d" % repo.id) if os.path.exists(path): tools_list.extend(load_one_dir(path)) for root, dirs, files in os.walk(path): if '.hg' in dirs: dirs.remove('.hg') for dirname in dirs: tools_in_dir = load_one_dir(os.path.join(root, dirname)) tools_list.extend(tools_in_dir) results.append( dict(id=repo_id, name=name, description=description, long_description=long_description, homepage_url=homepage_url, remote_repository_url=remote_repository_url, repo_owner_username=repo_owner_username, times_downloaded=times_downloaded, approved=approved, last_updated=last_updated, full_last_updated=full_last_updated, tools_list=tools_list, repo_lineage=repo_lineage, categories=categories)) return results
def get_repos(sa_session, file_path, hgweb_config_dir, **kwargs): """ Load repos from DB and included tools from .xml configs. """ hgwcm = hgweb_config_manager hgwcm.hgweb_config_dir = hgweb_config_dir # Do not index deleted, deprecated, or "tool_dependency_definition" type repositories. q = sa_session.query(model.Repository).filter_by(deleted=False).filter_by( deprecated=False).order_by(model.Repository.update_time.desc()) q = q.filter(model.Repository.type != 'tool_dependency_definition') for repo in q: category_names = [] for rca in sa_session.query( model.RepositoryCategoryAssociation ).filter(model.RepositoryCategoryAssociation.repository_id == repo.id): for category in sa_session.query(model.Category).filter( model.Category.id == rca.category.id): category_names.append(category.name.lower()) categories = (",").join(category_names) repo_id = repo.id name = repo.name description = repo.description long_description = repo.long_description homepage_url = repo.homepage_url remote_repository_url = repo.remote_repository_url times_downloaded = repo.times_downloaded or 0 repo_owner_username = '' if repo.user_id is not None: user = sa_session.query( model.User).filter(model.User.id == repo.user_id).one() repo_owner_username = user.username.lower() approved = 'no' for review in repo.reviews: if review.approved == 'yes': approved = 'yes' break last_updated = pretty_print_time_interval(repo.update_time) full_last_updated = repo.update_time.strftime("%Y-%m-%d %I:%M %p") # Load all changesets of the repo for lineage. repo_path = os.path.join( hgweb_config_dir, hgwcm.get_entry( os.path.join("repos", repo.user.username, repo.name))) hg_repo = hg.repository(ui.ui(), repo_path.encode('utf-8')) lineage = [] for changeset in hg_repo.changelog: lineage.append( unicodify(changeset) + ":" + unicodify(hg_repo[changeset])) repo_lineage = str(lineage) # Parse all the tools within repo for a separate index. tools_list = [] path = os.path.join(file_path, *directory_hash_id(repo.id)) path = os.path.join(path, "repo_%d" % repo.id) if os.path.exists(path): tools_list.extend(load_one_dir(path)) for root, dirs, _files in os.walk(path): if '.hg' in dirs: dirs.remove('.hg') for dirname in dirs: tools_in_dir = load_one_dir(os.path.join(root, dirname)) tools_list.extend(tools_in_dir) yield (dict(id=unicodify(repo_id), name=unicodify(name), description=unicodify(description), long_description=unicodify(long_description), homepage_url=unicodify(homepage_url), remote_repository_url=unicodify(remote_repository_url), repo_owner_username=unicodify(repo_owner_username), times_downloaded=unicodify(times_downloaded), approved=unicodify(approved), last_updated=unicodify(last_updated), full_last_updated=unicodify(full_last_updated), tools_list=tools_list, repo_lineage=unicodify(repo_lineage), categories=unicodify(categories)))