class ProjectList(object): def __init__(self, project_list, tagsonomy): self.project_list = [] self.tagsonomy = tagsonomy self.tag_registry = OMD() self.tag_alias_map = OMD() for tag in self.tagsonomy['topic']: self.register_tag('topic', tag) for project in project_list: self.project_list.append(Project.from_dict(project)) @classmethod def from_path(cls, path): data = yaml.safe_load(open(path)) return cls(data['projects'], data['tagsonomy']) def register_tag(self, tag_type, tag_entry, tag_path=()): if isinstance(tag_entry, str): tag, tag_entry = tag_entry, {} else: tag, tag_entry = _unwrap_dict(tag_entry) tag_entry = dict(tag_entry) tag_entry['tag'] = tag tag_entry['tag_type'] = tag_type if not tag_entry.get('title'): tag_entry["title"] = tag.replace('_', ' ').title() subtags = [] for subtag_entry in tag_entry.pop('subtags', []): st = self.register_tag( tag_type, subtag_entry, tag_path=(tag, ) if not tag_path else tag_path + (tag, )) subtags.append(st) tag_entry['subtags'] = tuple(subtags) tag_entry['fq_tag'] = '.'.join(tag_path + (tag, )) if not tag_path: ret = TagEntry(**tag_entry) else: ret = TagEntry(tag_path=tag_path, **tag_entry) self.tag_registry[tag] = ret return ret def get_projects_by_type(self, type_name): ret = OMD() for tag, tag_entry in self.tag_registry.items(): if tag_entry.tag_type != type_name: continue ret[tag_entry] = [] for project in self.project_list: if tag in project.tags: ret[tag_entry].append(project) ret[tag_entry].sort(key=lambda x: x.name) return ret
def test_invert(): for items in _ITEMSETS: omd = OMD(items) iomd = omd.inverted() # first, test all items made the jump assert len(omd.items(multi=True)) == len(iomd.items(multi=True)) for val in omd.values(): assert val in iomd # all values present as keys
def test_kv_consistency(): for itemset in _ITEMSETS: omd = OMD(itemset) for multi in (True, False): items = omd.items(multi=multi) keys = omd.keys(multi=multi) values = omd.values(multi=multi) assert keys == [x[0] for x in items] assert values == [x[1] for x in items] return
def test_pop(): omd = OMD() omd.add('even', 0) omd.add('odd', 1) omd.add('even', 2) assert omd.pop('odd') == 1 assert omd.pop('odd', 99) == 99 try: omd.pop('odd') assert False except KeyError: pass assert len(omd) == 1 assert len(omd.items(multi=True)) == 2
def test_pop(): omd = OMD() omd.add('even', 0) omd.add('odd', 1) omd.add('even', 2) assert omd.pop('odd') == 1 assert omd.pop('odd', 99) == 99 try: omd.pop('odd') import pdb;pdb.set_trace() assert False except KeyError: pass assert len(omd) == 1 assert len(omd.items(multi=True)) == 2
def test_pop(): omd = OMD() omd.add("even", 0) omd.add("odd", 1) omd.add("even", 2) assert omd.pop("odd") == 1 assert omd.pop("odd", 99) == 99 try: omd.pop("odd") import pdb pdb.set_trace() assert False except KeyError: pass assert len(omd) == 1 assert len(omd.items(multi=True)) == 2
def _get_pkg_info(plist, project, repo_dir): # snap: search for snapcraft.yaml # appimage: find -iname "appimage" -type d # flatpak: find -iname "flatpak" -type d # maybe exclude test dirs, e.g., what ansible has # docker: find -name "Dockerfile" ret = {} container_stacks = OMD() for path in iter_find_files(repo_dir, CONTAINER_FILES, include_dirs=True): container_stacks.add( os.path.splitext(os.path.basename(path))[0].lower(), path) #if container_stacks: # print(container_stacks.todict()) has_docker = bool(container_stacks.pop('dockerfile', None)) container_stack = first(container_stacks.keys(), None) or ('docker' if has_docker else '') ret['container'] = container_stack # TODO: split into mac/windows/linux? for linux I'll need to look # at deb/rpm, and I'm not sure the best strategy there. rpm maybe # .spec files? might have to check inside as other tools # (pyinstaller) uses .spec, too. # freezers -> pyInstaller, cx_Freeze, py2exe, py2app, pynsist # (bbFreeze phased out, osnap/constructor not yet adopted, harder # to search for). conda and omnibus also not adopted. freezer_res_map = OMD() for freezer_name in FREEZERS: search_output = search_files(freezer_name, '*', repo_dir) if search_output: freezer_res_map.add(freezer_name, len(search_output.splitlines())) if freezer_res_map: top, top_res = sorted(freezer_res_map.items(), key=lambda x: x[1])[-1] ret['freezer'] = top return ret
class ProjectList(object): def __init__(self, project_list, tagsonomy): self.project_list = [] self.tagsonomy = tagsonomy self.tag_registry = OMD() for tag_group in ('topic', 'platform'): # TODO: framework, license for tag in self.tagsonomy[tag_group]: self.register_tag(tag_group, tag) errors = [] for project in project_list: new_tags = tuple( soft_sorted(project.get('tags', []), first=self.tag_registry.keys())) project['tags'] = new_tags try: project_obj = Project.from_dict(project) except ApatiteError as ae: errors.append(ae) continue self.project_list.append(project_obj) dupe_groups = redundant(self.project_list, key=lambda p: slugify(p.name), groups=True) dupe_groups += redundant(self.project_list, key=lambda p: p.repo_url, groups=True) dupe_groups = unique([tuple(dg) for dg in dupe_groups]) for group in dupe_groups: dpe = DuplicateProjectError('ambiguous or duplicate projects: %r' % [p.name for p in group]) errors.append(dpe) if errors: raise ProjectListError.from_errors(errors) return @classmethod def from_path(cls, path): data = round_trip_load(open(path, encoding='utf-8')) return cls(data['projects'], data['tagsonomy']) def to_dict(self): ret = CommentedMap() ret.yaml_set_start_comment('\n' + PLIST_PREFACE_COMMENT + '\n\n') ret['tagsonomy'] = self.tagsonomy plist = [] seen_topics = set() for p in self.project_list: cur_pdict = p.to_dict() plist.append(cur_pdict) # now, determine whether to emit a comment topic_tags = [ t for t in p._tags if t in self.tag_registry and self.tag_registry[t].tag_type == 'topic' ] if not topic_tags: continue first_topic = topic_tags[0] if first_topic in seen_topics: continue seen_topics.add(first_topic) cur_pdict.yaml_set_start_comment('\n' + first_topic.title() + '\n\n') ret['projects'] = plist return ret def to_yaml(self): return to_yaml(self.to_dict()) def normalize(self): # sort project list by first topic tag and name (lexi). tag_list = list(self.tag_registry.keys()) def plist_sort_key(project): topic_tags = [ t for t in project._tags if t in self.tag_registry and self.tag_registry[t].tag_type == 'topic' ] first_topic = topic_tags[ 0] if topic_tags else 'misc' # TODO: might change to uncategorized in future first_topic_idx = tag_list.index(first_topic) return (first_topic_idx, project.name.lower()) project_list = [] for project in sorted(self.project_list, key=plist_sort_key): if not project.desc[-1:] in ').!': project = attr.evolve(project, desc=project.desc + '.') cleaned_urls = [] for url_name, url in project.urls: # strip off trailing slashes from all urls new_path = tuple([segm for segm in url.path if segm != '']) clean_url = url.replace(path=new_path).normalize() cleaned_urls.append((url_name, clean_url)) project = attr.evolve(project, urls=cleaned_urls) project_list.append(project) self.project_list = project_list return def register_tag(self, tag_type, tag_entry, tag_path=()): if isinstance(tag_entry, str): tag, tag_entry = tag_entry, {} else: tag, tag_entry = _unwrap_dict(tag_entry) tag_entry = dict(tag_entry) tag_entry['tag'] = tag tag_entry['tag_type'] = tag_type if not tag_entry.get('title'): tag_entry["title"] = tag.replace('_', ' ').title() subtags = [] for subtag_entry in tag_entry.pop('subtags', []): st = self.register_tag( tag_type, subtag_entry, tag_path=(tag, ) if not tag_path else tag_path + (tag, )) subtags.append(st) tag_entry['subtags'] = tuple(subtags) tag_entry['fq_tag'] = '.'.join(tag_path + (tag, )) if not tag_path: ret = TagEntry(**tag_entry) else: ret = TagEntry(tag_path=tag_path, **tag_entry) self.tag_registry[tag] = ret return ret def get_projects_by_type(self, type_name): ret = OMD() for tag, tag_entry in self.tag_registry.items(): if tag_entry.tag_type != type_name: continue ret[tag_entry] = [] for project in self.project_list: if tag in project._tags: ret[tag_entry].append(project) ret[tag_entry].sort(key=lambda x: x.name.lower()) return ret
class ProjectList(object): def __init__(self, project_list, tagsonomy): self.project_list = [] self.tagsonomy = tagsonomy self.tag_registry = OMD() for tag_group in ('topic', 'platform'): # TODO: framework, license for tag in self.tagsonomy[tag_group]: self.register_tag(tag_group, tag) for project in project_list: new_tags = soft_sorted(project.get('tags', []), first=self.tag_registry.keys()) project['tags'] = new_tags self.project_list.append(Project.from_dict(project)) @classmethod def from_path(cls, path): data = round_trip_load(open(path, encoding='utf-8')) return cls(data['projects'], data['tagsonomy']) def to_dict(self): ret = CommentedMap() ret['tagsonomy'] = self.tagsonomy plist = [] seen_topics = set() for p in self.project_list: cur_pdict = p.to_dict() plist.append(cur_pdict) # now, determine whether to emit a comment topic_tags = [t for t in p.tags if t in self.tag_registry and self.tag_registry[t].tag_type == 'topic'] if not topic_tags: continue first_topic = topic_tags[0] if first_topic in seen_topics: continue seen_topics.add(first_topic) cur_pdict.yaml_set_start_comment('\n' + first_topic.title() + '\n\n') ret['project_list'] = plist return ret def to_yaml(self): return to_yaml(self.to_dict()) def normalize(self): # sort project list by first topic tag and name (lexi). tag_list = list(self.tag_registry.keys()) def plist_sort_key(project): topic_tags = [t for t in project.tags if t in self.tag_registry and self.tag_registry[t].tag_type == 'topic'] first_topic = topic_tags[0] if topic_tags else 'misc' # TODO: might change to uncategorized in future first_topic_idx = tag_list.index(first_topic) return (first_topic_idx, project.name.lower()) project_list = [] for project in sorted(self.project_list, key=plist_sort_key): if not project.desc[-1:] in ').': project = attr.evolve(project, desc=project.desc + '.') project_list.append(project) self.project_list = project_list return def register_tag(self, tag_type, tag_entry, tag_path=()): if isinstance(tag_entry, str): tag, tag_entry = tag_entry, {} else: tag, tag_entry = _unwrap_dict(tag_entry) tag_entry = dict(tag_entry) tag_entry['tag'] = tag tag_entry['tag_type'] = tag_type if not tag_entry.get('title'): tag_entry["title"] = tag.replace('_', ' ').title() subtags = [] for subtag_entry in tag_entry.pop('subtags', []): st = self.register_tag(tag_type, subtag_entry, tag_path=(tag,) if not tag_path else tag_path + (tag,)) subtags.append(st) tag_entry['subtags'] = tuple(subtags) tag_entry['fq_tag'] = '.'.join(tag_path + (tag,)) if not tag_path: ret = TagEntry(**tag_entry) else: ret = TagEntry(tag_path=tag_path, **tag_entry) self.tag_registry[tag] = ret return ret def get_projects_by_type(self, type_name): ret = OMD() for tag, tag_entry in self.tag_registry.items(): if tag_entry.tag_type != type_name: continue ret[tag_entry] = [] for project in self.project_list: if tag in project.tags: ret[tag_entry].append(project) ret[tag_entry].sort(key=lambda x: x.name.lower()) return ret