"""Text formatting utilities."""from__future__importannotationsimportioimportrefromfunctoolsimportpartialfrompprintimportpformatfromreimportMatchfromtextwrapimportfillfromtypingimportAny,Callable,Pattern__all__=('abbr','abbrtask','dedent','dedent_initial','ensure_newlines','ensure_sep','fill_paragraphs','indent','join','pluralize','pretty','str_to_list','simple_format','truncate',)UNKNOWN_SIMPLE_FORMAT_KEY="""Unknown format %{0} in string {1!r}.Possible causes: Did you forget to escape the expand sign (use '%%{0!r}'),or did you escape and the value was expanded twice? (%%N -> %N -> %hostname)?""".strip()RE_FORMAT=re.compile(r'%(\w)')
[文档]defstr_to_list(s:str)->list[str]:"""Convert string to list."""ifisinstance(s,str):returns.split(',')returns
[文档]defdedent_initial(s:str,n:int=4)->str:"""Remove indentation from first line of text."""returns[n:]ifs[:n]==' '*nelses
[文档]deftruncate(s:str,maxlen:int=128,suffix:str='...')->str:"""Truncate text to a maximum number of characters."""ifmaxlenandlen(s)>=maxlen:returns[:maxlen].rsplit(' ',1)[0]+suffixreturns
[文档]defpluralize(n:float,text:str,suffix:str='s')->str:"""Pluralize term when n is greater than one."""ifn!=1:returntext+suffixreturntext
[文档]defpretty(value:str,width:int=80,nl_width:int=80,sep:str='\n',**kw:Any)->str:"""Format value for printing to console."""ifisinstance(value,dict):returnf'{sep}{pformat(value,4,nl_width)[1:]}'elifisinstance(value,tuple):return'{}{}{}'.format(sep,' '*4,pformat(value,width=nl_width,**kw),)else:returnpformat(value,width=width,**kw)
[文档]defsimple_format(s:str,keys:dict[str,str|Callable],pattern:Pattern[str]=RE_FORMAT,expand:str=r'\1')->str:"""Format string, expanding abbreviations in keys'."""ifs:keys.setdefault('%','%')defresolve(match:Match)->str|Any:key=match.expand(expand)try:resolver=keys[key]exceptKeyError:raiseValueError(UNKNOWN_SIMPLE_FORMAT_KEY.format(key,s))ifcallable(resolver):returnresolver()returnresolverreturnpattern.sub(resolve,s)returns
defremove_repeating_from_task(task_name:str,s:str)->str:"""Given task name, remove repeating module names. Example: >>> remove_repeating_from_task( ... 'tasks.add', ... 'tasks.add(2, 2), tasks.mul(3), tasks.div(4)') 'tasks.add(2, 2), mul(3), div(4)' """# This is used by e.g. repr(chain), to remove repeating module names.# - extract the module part of the task namemodule=str(task_name).rpartition('.')[0]+'.'returnremove_repeating(module,s)defremove_repeating(substr:str,s:str)->str:"""Remove repeating module names from string. Arguments: task_name (str): Task name (full path including module), to use as the basis for removing module names. s (str): The string we want to work on. Example: >>> _shorten_names( ... 'x.tasks.add', ... 'x.tasks.add(2, 2) | x.tasks.add(4) | x.tasks.mul(8)', ... ) 'x.tasks.add(2, 2) | add(4) | mul(8)' """# find the first occurrence of substr in the string.index=s.find(substr)ifindex>=0:return''.join([# leave the first occurrence of substr untouched.s[:index+len(substr)],# strip seen substr from the rest of the string.s[index+len(substr):].replace(substr,''),])returnsStringIO=io.StringIO_SIO_write=StringIO.write_SIO_init=StringIO.__init__classWhateverIO(StringIO):"""StringIO that takes bytes or str."""def__init__(self,v:bytes|str|None=None,*a:Any,**kw:Any)->None:_SIO_init(self,v.decode()ifisinstance(v,bytes)elsev,*a,**kw)defwrite(self,data:bytes|str)->int:return_SIO_write(self,data.decode()ifisinstance(data,bytes)elsedata)