Mercurial > tracker > python-dev
view extensions/local_replace.py @ 560:0d0e7ce385e7 default tip
Make the CLA check case-insensitive, and use stringFind() instead of filter().
author | Ezio Melotti <ezio.melotti@gmail.com> |
---|---|
date | Tue, 11 Sep 2018 18:31:06 -0700 |
parents | 7d4942e1ce43 |
children |
line wrap: on
line source
import re import cgi from roundup import hyperdb from roundup.cgi.templating import register_propclass, StringHTMLProperty # pre-hg migration ''' substitutions = [ # r12345, r 12345, rev12345, rev 12345, revision12345, revision 12345 (re.compile(r'\b(?<![/?&;])(?P<revstr>r(ev(ision)?)?\s*)(?P<revision>\d+)'), r'<a href="http://svn.python.org/view?rev=\g<revision>' r'&view=rev">\g<revstr>\g<revision></a>'), # Lib/somefile.py, Modules/somemodule.c, Doc/somedocfile.rst, ... (re.compile(r'(?P<sep>(?<!\w/)|(?<!\w)/)(?P<path>(?:Demo|Doc|Grammar|' r'Include|Lib|Mac|Misc|Modules|Parser|PC|PCbuild|Python|' 'RISCOS|Tools|Objects)/[-.a-zA-Z0-9_/]+[a-zA-Z0-9]/?)'), r'<a href="http://svn.python.org/view/python/branches/' r'py3k/\g<path>">\g<sep>\g<path></a>'), ] ''' def make_file_link(match): """Convert files to links to the GitHub repo.""" baseurl = 'https://github.com/python/cpython/blob/' branch = match.group('v') or 'master/' # the match includes the '/' path = match.group('path') lnum = match.group('lnum') or '' # the match includes the ':' url = baseurl + branch + path if not path.endswith('/'): # files without and with line number if not lnum: return '<a href="%s">%s</a>' % (url, path) else: return '<a href="%s#L%s">%s%s</a>' % (url, lnum[1:], path, lnum) else: # dirs return '<a href="%s">%s</a>%s' % (url, path, lnum) def guess_version(path): """Search for Python version hints in the file path.""" match = re.search(r'((?<=[Pp]ython)[23]\d|[23]\.\d)', path) if not match: return 'master' version = match.group(1) if '.' not in version: version = '.'.join(version) if version in ['2.3', '2.4', '2.5', '2.6', '2.7', '3.1', '3.2', '3.3', '3.4', '3.5', '3.6', '3.7', '3.8', '3.9']: return version return 'master' def make_traceback_link(match): """Convert the file/line in the traceback lines in a link.""" baseurl = 'https://github.com/python/cpython/blob/' path = match.group('path') # first part of the path branch = guess_version(match.group('fullpath')) # guessed branch file = match.group('file') # second part after Lib/ nfile = file.replace('\\', '/') # normalize the path separators lnum = match.group('lnum') return ('File "%s<a href="%s%s/Lib/%s#L%s">%s</a>", line %s' % (path, baseurl, branch, nfile, lnum, file, lnum)) def make_pep_link(match): text = match.group(0) pepnum = match.group(1).zfill(4) return '<a href="http://www.python.org/dev/peps/pep-%s/">%s</a>' % (pepnum, text) # these regexs have test in tests/test_local_replace.py seps = r'\b(?<![-/?&;=_:])' # these chars should not precede the targets substitutions = [ # deadbeeffeed (hg hashes with exactly twelve or forty chars, # git has 10 or more as it grows as time goes on) (re.compile(r'%s(?P<revision>(git|hg)?[a-fA-F0-9]{40})\b' % seps), r'<a href="http://hg.python.org/lookup/\g<revision>">\g<revision></a>'), (re.compile(r'%s(?P<revision>(git|hg)?[a-fA-F0-9]{10,12})\b' % seps), r'<a href="http://hg.python.org/lookup/\g<revision>">\g<revision></a>'), # r12345, r 12345, rev12345, rev. 12345, revision12345, revision 12345 (re.compile(r'%s(?P<revstr>r\.?(ev\.?(ision)?)?\s*)(?P<revision>\d{4,})' % seps), r'<a href="http://hg.python.org/lookup/r\g<revision>">\g<revstr>\g<revision></a>'), # Lib/somefile.py, Lib/somefile.py:123, Modules/somemodule.c:123, ... (re.compile(r'%s(?P<v>2\.[0-7]/|3\.\d/)?(?P<path>(?:Demo|Doc|Grammar|' r'Include|Lib|Mac|Misc|Modules|Parser|PC|PCbuild|Python|' r'RISCOS|Tools|Programs|Objects)/' r'[-.\w/]+[a-zA-Z0-9]/?)(?P<lnum>:\d{1,5})?' % seps), make_file_link), # traceback lines: File "Lib/somefile.py", line 123 in some_func # note: this regex is not 100% accurate, it might get the wrong part of # the path or link to non-existing files, but it usually works fine (re.compile(r'File "(?P<fullpath>(?P<path>[-.\w/\\:]+(?<!var)[/\\][Ll]ib[/\\]' r'(?!.*site-packages)(python[\d.]*[/\\])?)(?P<file>[-.\w/\\]+?\.py))", ' r'line (?P<lnum>\d{1,5})'), make_traceback_link), # PEP 8, PEP8, PEP 0008, ... (re.compile(r'%s\b(?<![/=-])PEP\s*(\d{1,4})(?!/)\b' % seps, re.I), make_pep_link), # devguide (re.compile(r'%s(devguide(?:/\w+(?:.html)?(?:#[\w-]+)?)?)' % seps), r'<a href="http://docs.python.org/\1">\1</a>'), ] # if the issue number is too big the db will explode -- limit it to 7 digits issue_re = re.compile(r'(?P<text>((?<!\w)\#|\b(?<![-/_])(issue|bpo-))' r'\s*(?P<id>1?\d{1,6}))\b', re.I) # PR number, pull request number, pullrequest number pullrequest_re = re.compile(r'(?P<text>(\b(?<![-/_])(PR-?|GH-?|pull\s*request))\s*' r'(?P<pr_no>\d+))\b', re.I) class PyDevStringHTMLProperty(StringHTMLProperty): def _hyper_repl(self, match): """ Override the original method and change it to still linkify URLs and emails but avoid linkification of issues and other items (except messages and files). """ if match.group('url'): return self._hyper_repl_url(match, '<a href="%s">%s</a>%s') elif match.group('email'): return self._hyper_repl_email(match, '<a href="mailto:%s">%s</a>') elif (len(match.group('id')) < 10 and match.group('class') and match.group('class').lower() in ('msg', 'file')): # linkify msgs but not issues and other things return self._hyper_repl_item(match, '<a href="%(cls)s%(id)s">%(item)s</a>') else: # just return the matched text return match.group(0) def pydev_hyperlinked(self): """Create python-dev-specific links.""" # first do the normal linkification (without linkify the issues) message = self.plain(hyperlink=1) # then add links for revision numbers and paths for cre, replacement in substitutions: message = cre.sub(replacement, message) # finally add links for issues message = issue_re.sub(self._linkify_issue, message) message = pullrequest_re.sub(self._linkify_pull_request, message) return message def _linkify_issue(self, match): """Turn an issue (e.g. 'issue 1234' or '#1234') to an HTML link""" template = ('<a class="%(status)s" title="[%(status)s] %(title)s" ' 'href="issue%(issue_id)s">%(text)s</a>') issue_id = match.group('id') text = match.group('text') cl = self._db.issue # check if the issue exists if not cl.hasnode(issue_id): return text # get the title title = cgi.escape(cl.get(issue_id, 'title').replace('"', "'")) status_id = cl.get(issue_id, 'status') # get the name of the status if status_id is not None: status = self._db.status.get(status_id, 'name') else: status = 'none' return template % dict(issue_id=issue_id, title=title, status=status, text=text) def _linkify_pull_request(self, match): """Turn a pullrequest (e.g. 'PR 123') to an HTML link""" template = ('<a href="%(base_url)s%(pr_no)s" %(cls)s' 'title="GitHub PR %(pr_no)s%(info)s">%(text)s</a>') pr_no = match.group('pr_no') text = match.group('text') # find title and status cl = self._db.pull_request # find all the pull_request that refer to GitHub PR pr_no, # with the most recently updated first pr_ids = cl.filter(None, dict(number=pr_no), sort=[('-', 'activity')]) title = status = info = cls = '' for pr_id in pr_ids: if not title: title = cl.get(pr_id, 'title', '') if not status: status = cl.get(pr_id, 'status', '') if title and status: # once we get both, escape and add to info status = cgi.escape(status).replace('"', "'") title = cgi.escape(title).replace('"', "'") info = ': [%s] %s' % (status, title) break if status: cls = 'class="%s" ' % ('open' if status == 'open' else 'closed') base_url = 'https://github.com/python/cpython/pull/' return template % dict(base_url=base_url, pr_no=pr_no, cls=cls, info=info, text=text) noise_changes = re.compile('(nosy_count|message_count)\: \d+\.0( -> \d+\.0)?') def clean_count(history): history = noise_changes.sub('', history).replace('<td><br />', '<td>') return history def init(instance): register_propclass(hyperdb.String, PyDevStringHTMLProperty) instance.registerUtil('clean_count', clean_count)