def validate_campaign_id(_, __, id_text): if slugify(id_text) == id_text: return raise ValueError( 'expected campaign id to consist of lowercase printable characters,' ' with no punctuation except for underscores, like "%s", not %r' % (slugify(id_text), id_text))
def entry_root(self): entry_root = self.headers.get('entry_root', '') entry_base_path, entry_base_name = os.path.split(entry_root) if not entry_base_name: entry_base_name = slugify(self.title) elif entry_base_name.lower() != slugify(entry_base_name): raise ValueError('invalid custom entry_root: %r' % entry_root) entry_base_path = entry_base_path.strip('/') if entry_base_path: entry_base_path += '/' return entry_base_path + entry_base_name
def make_admin_round_details(rnd, rnd_stats): # TODO: This should be depricated in favor of rnd.to_details_dict(), which # is similar except for the stats dict structure. ret = { 'id': rnd.id, 'name': rnd.name, 'directions': rnd.directions, 'canonical_url_name': slugify(rnd.name, '-'), 'vote_method': rnd.vote_method, 'open_date': format_date(rnd.open_date), 'close_date': format_date(rnd.close_date), 'config': rnd.config, 'deadline_date': format_date(rnd.deadline_date), 'status': rnd.status, 'quorum': rnd.quorum, 'total_entries': len(rnd.entries), 'total_tasks': rnd_stats['total_tasks'], 'total_open_tasks': rnd_stats['total_open_tasks'], 'percent_tasks_open': rnd_stats['percent_tasks_open'], 'total_disqualified_entries': rnd_stats['total_disqualified_entries'], 'campaign': rnd.campaign.to_info_dict(), 'stats': rnd_stats, 'jurors': [rj.to_details_dict() for rj in rnd.round_jurors] } return ret
def download_results_csv(user_dao, round_id, request_dict): coord_dao = CoordinatorDAO.from_round(user_dao, round_id) rnd = coord_dao.get_round(round_id) now = datetime.datetime.now().isoformat() output_name = 'montage_results-%s-%s.csv' % (slugify(rnd.name, ascii=True), now) # TODO: Confirm round is finalized # raise DoesNotExist('round results not yet finalized') results_by_name = coord_dao.make_vote_table(round_id) output = io.BytesIO() csv_fieldnames = ['filename', 'average'] + [r.username for r in rnd.jurors] csv_writer = unicodecsv.DictWriter(output, fieldnames=csv_fieldnames, restval=None) # na means this entry wasn't assigned csv_writer.writeheader() for filename, ratings in results_by_name.items(): csv_row = {'filename': filename} valid_ratings = [r for r in ratings.values() if type(r) is not str] if valid_ratings: # TODO: catch if there are more than a quorum of votes ratings['average'] = sum(valid_ratings) / len(valid_ratings) else: ratings['average'] = 'na' csv_row.update(ratings) csv_writer.writerow(csv_row) ret = output.getvalue() resp = Response(ret, mimetype='text/csv') resp.mimetype_params['charset'] = 'utf-8' resp.headers['Content-Disposition'] = 'attachment; filename=%s' % output_name return resp
def cache_item_id(self, key) -> str: if not key: raise Exception("Must provide a cache key.") item_id = slugify(key, delim="_", ascii=True).decode("utf-8").strip().casefold() windows_invalid_chars = r"<>:\"/\|?*'" for windows_invalid_char in windows_invalid_chars: item_id = item_id.replace(windows_invalid_char, "_") return item_id
def update_projects(self, projects): to_update = OMD([(slugify(p.name), p) for p in projects]) new_list = [] for proj in self.project_list: if proj.name_slug not in to_update: new_list.append(proj) continue new_list.append(to_update.pop(proj.name_slug)) new_list.extend(to_update.values()) self.project_list = new_list
def __init__(self, raw_part, entry, part_idx, data_idx, data_consec_idx): super(DataPart, self).__init__(raw_part, entry, part_idx) self['data_idx'] = data_idx self['data_consec_idx'] = data_consec_idx ordinal_tmpl = self.entry.headers.get('ordinal_format') or '' self['ordinal_text'] = ordinal_tmpl.format(i=self['data_idx'], ci=self['data_consec_idx']) self['summary'] = self.get_builtin_value('summary') self['title'] = self.get_builtin_value('title', '') custom_slug = self.get_builtin_value('title_slug', '') title_slug = custom_slug or slugify(self['title']) if title_slug != slugify(title_slug): raise ValueError('invalid custom slug: %r' % custom_slug) self['title_slug'] = title_slug self['content'] = self.get_builtin_value('content') self['tags'] = self.get_builtin_value('tags', []) self.load_date() self.load_attrs()
def get_admin_campaign(): # rdb_session, user, campaign_id): """ Some non-API related facts. # API spec Summary: Get admin-level details for a campaign, identified by campaign ID. Request model: campaign_id: type: int64 Response model name: CampaignDetails Response model: id: type: int64 name: type: string rounds: type: array items: type: RoundDetails coordinators: type: array items: type: CoordDetails url_name: type: string Errors: 403: User does not have permission to access requested campaign 404: Campaign not found # End API spec More facts """ coord_dao = CoordinatorDAO(rdb_session=rdb_session, user=user) campaign = coord_dao.get_campaign(campaign_id) if campaign is None: raise Forbidden('not a coordinator on this campaign') info = { 'id': campaign.id, 'name': campaign.name, 'rounds': [], 'coords': [u.username for u in campaign.coords] } for rnd in campaign.rounds: info['rounds'].append(get_admin_round(rdb_session, user, rnd.id)) info['canonical_url_name'] = slugify(info['name'], '-') return info
def query_name(query: Mapping[str, Any]) -> str: """ Get a string name for the given query args. >>> query_name({'product': 'ls8_level1_scene'}) 'product_ls8_level1_scene' >>> query_name({'metadata_type': 'telemetry'}) 'metadata_type_telemetry' >>> query_name({'a': '1', 'b': 2, 'c': '"3"'}) 'a_1-b_2-c_3' """ return "-".join('{}_{}'.format(k, strutils.slugify(str(v))) for k, v in sorted(query.items()))
def download_round_entries_csv(user_dao, round_id): coord_dao = CoordinatorDAO.from_round(user_dao, round_id) rnd = coord_dao.get_round(round_id) entries = coord_dao.get_round_entries(round_id) entry_infos = [e.to_export_dict() for e in entries] output_name = 'montage_entries-%s.csv' % slugify(rnd.name, ascii=True) output = io.BytesIO() csv_fieldnames = sorted(entry_infos[0].keys()) csv_writer = unicodecsv.DictWriter(output, fieldnames=csv_fieldnames) csv_writer.writeheader() csv_writer.writerows(entry_infos) ret = output.getvalue() resp = Response(ret, mimetype='text/csv') resp.mimetype_params['charset'] = 'utf-8' resp.headers['Content-Disposition'] = 'attachment; filename=%s' % (output_name,) return resp
def make_juror_round_details(rnd, rnd_stats): ret = { 'id': rnd.id, 'directions': rnd.directions, 'name': rnd.name, 'vote_method': rnd.vote_method, 'open_date': format_date(rnd.open_date), 'close_date': format_date(rnd.close_date), 'deadline_date': format_date(rnd.deadline_date), 'status': rnd.status, 'canonical_url_name': slugify(rnd.name, '-'), 'config': rnd.config, 'total_tasks': rnd_stats['total_tasks'], 'total_open_tasks': rnd_stats['total_open_tasks'], 'percent_tasks_open': rnd_stats['percent_tasks_open'], 'campaign': rnd.campaign.to_info_dict() } return ret
def download(): output_file = StringIO() user_id = request.args.get("user_id") if user_id: if user_id not in users: abort(404) output_publications = publications.filter_by_user_id(user_id, include_denied=False) else: output_publications = publications.not_denied() output_csv = output_publications.to_csv(output_file) output = make_response(output_file.getvalue()) if user_id: user_name = slugify(users[user_id].full_name()) output.headers["Content-Disposition"] = "attachment; filename=%s_publications.csv" % user_name else: output.headers["Content-Disposition"] = "attachment; filename=publications.csv" output.headers["Content-type"] = "text/csv" return output
def from_dict(cls, d): validate_project_dict(d) kwargs = dict(d) tags = tuple([slugify(t) for t in kwargs.get('tags', ())]) dupe_groups = redundant(tags, groups=True) if dupe_groups: raise ProjectValidationError('duplicate tags in project %r: %r' % (kwargs['name'], dupe_groups)) kwargs['tags'] = tags cur_urls = () for k in list(kwargs): if not k.endswith('_url'): continue val = kwargs.pop(k) val = parse_valid_url(val) cur_urls += ((k[:-4], val), ) kwargs['urls'] = cur_urls kwargs['orig_data'] = d return cls(**kwargs)
def render_article_list(self): all_results = self._get_all_results() for goal in self.goals: goal['slug'] = slugify(goal['name']) ctx = { 'name': self.name, 'lang': self.lang, 'description': self.description, 'contacts': self.contacts, 'wikiproject_name': self.wikiproject_name, 'campaign_start_date': self.campaign_start_date.isoformat(), 'campaign_end_date': self.campaign_end_date.isoformat(), 'date_created': self.date_created.isoformat(), 'date_updated': datetime.datetime.utcnow().strftime(UPDATED_DT_FORMAT), 'article_count': len(self.article_title_list), 'all_results': all_results, 'goals': [{ 'name': 'Article', 'slug': 'title' }] + sorted(self.goals, key=lambda s: s['name']) } campaign_static_path = STATIC_PATH + 'campaigns/%s/' % self.id article_list_html = ASHES_ENV.render('articles.html', ctx) article_list_path = campaign_static_path + 'articles.html' article_list_json_path = campaign_static_path + 'articles.json' mkdir_p(os.path.split(article_list_path)[0]) with atomic_save(article_list_path) as html_f, atomic_save( article_list_json_path) as json_f: html_f.write(article_list_html.encode('utf-8')) json.dump(ctx, json_f, indent=2, sort_keys=True) return
def download(): output_file = StringIO() user_id = request.args.get("user_id") if user_id: if user_id not in users: abort(404) output_publications = publications.filter_by_user_id( user_id, include_denied=False) else: output_publications = publications.not_denied() output_csv = output_publications.to_csv(output_file) output = make_response(output_file.getvalue()) if user_id: user_name = slugify(users[user_id].full_name()) output.headers[ "Content-Disposition"] = "attachment; filename=%s_publications.csv" % user_name else: output.headers[ "Content-Disposition"] = "attachment; filename=publications.csv" output.headers["Content-type"] = "text/csv" return output
def __call__(self, key_prefix: bytes=b'', is_method: bool=False): if isinstance(key_prefix, str): key_prefix = slugify(key_prefix, ascii=True, lower=False) def _decorator(f): @wraps(f) def _decorated(*args, **kwargs): key_args = args[1:] if is_method else args key = key_prefix + self.cache.args_serializer(*key_args, ** kwargs) state, value = self.cache.get(key) if state != GetState.hit: value = f(*args, **kwargs) if state == GetState.miss: self.cache.set(key, value) return value return _decorated return _decorator
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
def is_match(self, query_track: Track, result_track: Track) -> bool: query_new = Track.create( query_track.origin_code, query_track.track_id, query_track.title, query_track.artists, query_track.info, ) query_title = slugify(query_new.title) query_artist = slugify(query_new.artists[0]) query_featured = slugify(", ".join(query_new.artists[1:])) result_new = Track.create( result_track.origin_code, result_track.track_id, result_track.title, result_track.artists, result_track.info, ) result_title = slugify(result_new.title) result_artist = slugify(result_new.artists[0]) result_featured = slugify(", ".join(result_new.artists[1:])) match_title = query_title in result_title # match_artist = query_artist in result_artist match_featuring = query_featured in result_featured match_featuring2 = result_featured in query_featured equal_title = query_title == result_title equal_artist = query_artist == result_artist # equal_featuring = query_featured == result_featured has_featuring = query_featured and result_featured # these are the variations that are valid if equal_title and equal_artist and match_featuring and has_featuring: return True if match_title and equal_artist and match_featuring and not has_featuring: return True if (equal_title and equal_artist and has_featuring and (match_featuring or match_featuring2)): return True return False
def __init__(self, bot_name: str, owner_id: int, token: str, description: str = None, case_insensitive: bool = True, specified_cogs: List[str] = None, loop=None): """ Create a new bot. Must provide the bot name, bot owner id, and bot token. May provide a bot description, bot sensitivity to text case, bot cogs, and bot custom loop. """ self.bot_name = bot_name self.logger = logging.getLogger(slugify(bot_name, delim='-') + '-log') self.owner_id = owner_id self.case_insensitive = case_insensitive self.loop = loop self.token = token self.description = description if specified_cogs: self.known_cogs = specified_cogs
def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name, "-") super().save(*args, **kwargs)
def _make_anchor_id(self, header_text): return slugify(header_text, delim=self.get_config('site', 'anchor_delim', '-'))
def species_filename(species): return slugify(species).lower()+'.json'
def get_project(self, name): name_slug = slugify(name) for proj in self.project_list: if proj.name_slug == name_slug: return proj raise LookupError('no such project: %r' % name)
#!/usr/bin/env python3 from boltons.strutils import slugify import pyo3_mixed assert pyo3_mixed.get_42() == 42 assert slugify("First post! Hi!!!!~1 ") == "first_post_hi_1" print("SUCCESS")
def from_api(cls, campaign, timestamp=None): timestamp = timestamp if timestamp is not None else datetime.datetime.utcnow( ) ret = cls(campaign=campaign, timestamp=timestamp, campaign_results=None, goal_results=None, article_results=None) article_list = [] article_title_list = campaign.article_title_list base_desc = 'Scanning %s @ %s' % (campaign.name, timestamp.isoformat().split('.')[0]) article_title_list = tqdm( article_title_list, desc=base_desc, disable=None, # autodisable on non-tty unit='article') def async_pta_update(pta, attr_func_map): jobs = [] for attr, func in attr_func_map.items(): _debug_log_func = tlog.wrap('debug')(func) cur = gevent.spawn( lambda pta=pta, attr=attr, func=_debug_log_func: setattr( pta, attr, func(pta))) jobs.append(cur) gevent.wait(jobs, timeout=20) return for title in article_title_list: new_desc = base_desc + ' ({:16.16})'.format(title) article_title_list.set_description(new_desc) pta = PTArticle(lang=campaign.lang, title=title, timestamp=timestamp) pta.talk_title = 'Talk:' + title async_pta_update(pta, { 'rev_id': metrics.get_revid, 'talk_rev_id': metrics.get_talk_revid }) if pta.rev_id: async_pta_update( pta, { 'templates': metrics.get_templates, 'talk_templates': metrics.get_talk_templates, 'assessments': metrics.get_assessments, 'citations': metrics.get_citations, 'wikidata_item': metrics.get_wikidata_item }) pta.wikiprojects = metrics.get_wikiprojects( pta) # relies on templates (no network) pta.results = eval_article_goals(pta, campaign.goals) article_list.append(pta) ret.article_list = article_list gres = {} # goal results for goal in campaign.goals: key = slugify(goal['name']) target_ratio = float(goal.get('ratio', 1.0)) results = [a.results[key]['done'] for a in article_list] # TODO: average/median metric value done, not_done = partition(results) # TODO: need to integrate start state for progress tracking ratio = 1.0 if not not_done else float( len(done)) / len(article_list) gres[key] = { 'done_count': len(done), 'not_done_count': len(not_done), 'total_count': len(article_list), 'ratio': ratio, 'target_ratio': target_ratio, 'key': key, 'name': goal['name'], 'desc': goal.get('desc'), 'progress': ratio / target_ratio, 'done': ratio >= target_ratio } ret.campaign_results = glom( gres, { 'done_count': (T.values(), ['done_count'], sum), 'not_done_count': (T.values(), ['not_done_count'], sum), 'total_count': (T.values(), ['total_count'], sum) }) ret.campaign_results['ratio'] = ret.campaign_results[ 'done_count'] / ret.campaign_results['total_count'] ret.goal_results = gres ret.article_results = [attr.asdict(a) for a in article_list] return ret
def subdivision_type_id(subdivision: pycountry.Subdivision) -> str: r"""Normalize subdivision type name into a Python-friendly ID. Here is the list of all subdivision types defined by ``pycountry`` v1.8:: >>> print('\n'.join(sorted({x.type for x in subdivisions}))) Administration Administrative Region Administrative Territory Administrative atoll Administrative region Arctic Region Area Autonomous City Autonomous District Autonomous Province Autonomous Region Autonomous city Autonomous community Autonomous municipality Autonomous province Autonomous region Autonomous republic Autonomous sector Autonomous territorial unit Borough Canton Capital District Capital Metropolitan City Capital Territory Capital city Capital district Capital territory Chains (of islands) City City corporation City with county rights Commune Constitutional province Council area Country County Department Dependency Development region District District council area Division Economic Prefecture Economic region Emirate Entity Federal Dependency Federal District Federal Territories Federal district Geographical Entity Geographical region Geographical unit Governorate Included for completeness Indigenous region Island Island council Island group Local council London borough Metropolitan cities Metropolitan department Metropolitan district Metropolitan region Municipalities Municipality Oblast Outlying area Overseas region/department Overseas territorial collectivity Parish Popularates Prefecture Province Quarter Rayon Region Regional council Republic Republican City Self-governed part Special District Special Municipality Special Region Special administrative region Special city Special island authority Special municipality Special zone State Territorial unit Territory Town council Two-tier county Union territory Unitary authority Unitary authority (England) Unitary authority (Wales) district state zone This method transform and normalize any of these into Python-friendly IDs. """ type_id = slugify(subdivision.type) # Any occurence of the 'city' or 'municipality' string in the type # overrides its classification to a city. if {"city", "municipality"} & set(type_id.split("_")): type_id = "city" return type_id
def slugify(text: str): return strutils.slugify(text, delim='_', lower=True)
def _slug(self, value): return slugify(str(value), lower=True)
def species_filename(species): return slugify(species).lower() + '.json'
def get_playlist_tracks(self, limit: Optional[int] = None) -> List[Track]: # build dates for urls current_time = datetime.now(tz=self._time_zone) date_from = current_time - timedelta(days=7) date_to = current_time # download 4zzz programs programs = self._downloader.download_json(self._downloader.cache_temp, self._url) tracks = {} # programs for program in programs: if program.get("archived"): continue program_name = program["name"] # episodes episodes_url = f"{program['programRestUrl']}/episodes" episodes = self._downloader.download_json( self._downloader.cache_temp, episodes_url) for episode in episodes or []: episode_start = datetime.strptime( episode["start"], "%Y-%m-%d %H:%M:%S").replace(tzinfo=self._time_zone) episode_end = datetime.strptime( episode["end"], "%Y-%m-%d %H:%M:%S").replace(tzinfo=self._time_zone) if (date_from > episode_start or date_to < episode_start or date_from > episode_end or date_to < episode_end): continue # playlist tracks playlist_url = f"{episode['episodeRestUrl']}/playlists" playlist_raw = self._downloader.download_json( self._downloader.cache_persisted, playlist_url) for track in playlist_raw or []: track_type = track["type"] track_artist = track["artist"] track_title = track["title"] track_track = track["track"] if track_type != "track": raise Exception( f"Track type is expected to be 'track', but is {track_type}." ) if track_title != track_track: raise Exception( f"Title and track are expected to match, but do not: '{track_title}' != '{track_track}'" ) track_key = "-".join([ slugify(track_artist, delim="-", ascii=True).decode("utf-8"), slugify(track_track, delim="-", ascii=True).decode("utf-8"), ]) item = { "type": track_type, "id": track["id"], "artist": track_artist, "title": track_title, "track": track_track, "release": track["release"], "time": track["time"], "notes": track["notes"], "twitter": track["twitterHandle"], "is_australian": track["contentDescriptors"]["isAustralian"], "is_local": track["contentDescriptors"]["isLocal"], "is_female": track["contentDescriptors"]["isFemale"], "is_indigenous": track["contentDescriptors"]["isIndigenous"], "is_new": track["contentDescriptors"]["isNew"], "wikipedia": track["wikipedia"], "image": track["image"], "video": track["video"], "url": track["url"], "approximate_time": track["approximateTime"], "program_name": program_name, "episode_start": episode_start, } if track_key in tracks: tracks[track_key].append(item) else: tracks[track_key] = [item] # find the top 50 most played tracks most_played_tracks = sorted([(len(v), k, v) for k, v in tracks.items() if len(v) > 1], reverse=True)[:100] # build the source playlist tracks result = [] for index, most_played_track in enumerate(most_played_tracks): play_count = most_played_track[0] track_id = most_played_track[1] track_info = most_played_track[2] info = self._build_info(track_id, play_count, track_info) title = info.get("title") artists = [info.get("artist")] result.append( Track.create(self.code, track_id, title, artists, info)) self._logger.info(f"Retrieved {self.title} with {len(result)} tracks.") if limit is not None and 0 < limit < len(result): result = result[:limit] return result
def _create_code(self, *args): result = slugify('-'.join([i for i in args if i]), delim='-') return result
def tex_file(*args): from boltons.strutils import slugify return slugify(' '.join(args)) + '.tex'
def subdivision_type_id(subdivision): """ Normalize subdivision type name into a Python-friendly ID. Here is the list of all subdivision types defined by ``pycountry`` v1.8:: >>> print '\n'.join(sorted(set([x.type for x in subdivisions]))) Administration Administrative Region Administrative Territory Administrative atoll Administrative region Arctic Region Area Autonomous City Autonomous District Autonomous Province Autonomous Region Autonomous city Autonomous community Autonomous municipality Autonomous province Autonomous region Autonomous republic Autonomous sector Autonomous territorial unit Borough Canton Capital District Capital Metropolitan City Capital Territory Capital city Capital district Capital territory Chains (of islands) City City corporation City with county rights Commune Constitutional province Council area Country County Department Dependency Development region District District council area Division Economic Prefecture Economic region Emirate Entity Federal Dependency Federal District Federal Territories Federal district Geographical Entity Geographical region Geographical unit Governorate Included for completeness Indigenous region Island Island council Island group Local council London borough Metropolitan cities Metropolitan department Metropolitan district Metropolitan region Municipalities Municipality Oblast Outlying area Overseas region/department Overseas territorial collectivity Parish Popularates Prefecture Province Quarter Rayon Region Regional council Republic Republican City Self-governed part Special District Special Municipality Special Region Special administrative region Special city Special island authority Special municipality Special zone State Territorial unit Territory Town council Two-tier county Union territory Unitary authority Unitary authority (England) Unitary authority (Wales) district state zone This method transform and normalize any of these into Python-friendly IDs. """ type_id = slugify(subdivision.type) # Any occurence of the 'city' or 'municipality' string in the type # overrides its classification to a city. if set(['city', 'municipality']).intersection(type_id.split('_')): type_id = 'city' return type_id
def name_slug(self): return slugify(self.name)
def eval_article_goals(pta, goals): ret = {} for goal in goals: # maybe default name to metric name, need to precheck they don't collide ret[slugify(goal['name'])] = eval_one_article_goal(pta, goal) return ret