Commits

anatoly techtonik committed f0cb193

Allow callables for replacements in regexp rules created with helper.

  • Participants
  • Parent commits f2ba7d7
  • Tags 0.3

Comments (0)

Files changed (3)

tests/data_python_tracker.txt

 I uploaded <a href="http://pypi.python.org/pypi/ctypesgen/0.r125">http://pypi.python.org/pypi/ctypesgen/0.r125</a>
 ##
 ##
+see PEP 8
+see <a href="http://www.python.org/dev/peps/pep-0008/">PEP 8</a>
+see PEP8
+see <a href="http://www.python.org/dev/peps/pep-0008/">PEP8</a>
+see pep 8
+see <a href="http://www.python.org/dev/peps/pep-0008/">pep 8</a>
+see PEP 008
+see <a href="http://www.python.org/dev/peps/pep-0008/">PEP 008</a>
+see PEP 3000
+see <a href="http://www.python.org/dev/peps/pep-3000/">PEP 3000</a>
+see PEP 15000
+see PEP 15000
+write a PEP!
+write a PEP!
+http://wiki.python.org/moin/SummerOfCode/2011/PEP393
+<a href="http://wiki.python.org/moin/SummerOfCode/2011/PEP393">http://wiki.python.org/moin/SummerOfCode/2011/PEP393</a>
+see https://bitbucket.org/rndblnch/cpython-pep380/raw/tip/pep380
+see <a href="https://bitbucket.org/rndblnch/cpython-pep380/raw/tip/pep380">https://bitbucket.org/rndblnch/cpython-pep380/raw/tip/pep380</a>
+see https://bitbucket.org/rndblnch/cpython-pep380/wiki
+see <a href="https://bitbucket.org/rndblnch/cpython-pep380/wiki">https://bitbucket.org/rndblnch/cpython-pep380/wiki</a>
+see http://www.python.org/dev/peps/pep-0008/
+see <a href="http://www.python.org/dev/peps/pep-0008/">http://www.python.org/dev/peps/pep-0008/</a>
+##
+##
 see the devguide.
 see the <a href="http://docs.python.org/devguide">devguide</a>.
 see http://docs.python.org/devguide/.
 see devguide/committing#using-several-working-copies
 see <a href="http://docs.python.org/devguide/committing#using-several-working-copies">devguide/committing#using-several-working-copies</a>
 ##
+## files - Lib/somefile.py, Modules/somemodule.c, Doc/somedocfile.rst, ...
+Lib/cgi.py
+<a href="http://hg.python.org/cpython/file/default/Lib/cgi.py">Lib/cgi.py</a>
+/Lib/cgi.py
+<a href="http://hg.python.org/cpython/file/default/Lib/cgi.py">/Lib/cgi.py</a>
+see Lib/cgi.py.
+see <a href="http://hg.python.org/cpython/file/default/Lib/cgi.py">Lib/cgi.py</a>.
+see /Lib/cgi.py.
+see <a href="http://hg.python.org/cpython/file/default/Lib/cgi.py">/Lib/cgi.py</a>.
+(Lib/cgi.py)
+(<a href="http://hg.python.org/cpython/file/default/Lib/cgi.py">Lib/cgi.py</a>)
+(/Lib/cgi.py)
+(<a href="http://hg.python.org/cpython/file/default/Lib/cgi.py">/Lib/cgi.py</a>)
+/Lib/http
+<a href="http://hg.python.org/cpython/file/default/Lib/http">/Lib/http</a>
+/Lib/http/
+<a href="http://hg.python.org/cpython/file/default/Lib/http/">/Lib/http/</a>
+##
+## files with line number - Lib/somefile.py:123, Modules/somemodule.c:123, ...
+see Lib/cgi.py:123,
+see <a href="http://hg.python.org/cpython/file/default/Lib/cgi.py#l123">Lib/cgi.py:123</a>,
+see Lib/cgi.py: foo
+see <a href="http://hg.python.org/cpython/file/default/Lib/cgi.py">Lib/cgi.py</a>: foo
+see Lib/cgi.py: 123
+see <a href="http://hg.python.org/cpython/file/default/Lib/cgi.py">Lib/cgi.py</a>: 123
+/Lib/http/:123
+<a href="http://hg.python.org/cpython/file/default/Lib/http/">/Lib/http/</a>:123
+##
+## tracebacks
+File "/usr/lib/python2.7/socket.py", line 553, in create_connection
+File "/usr/lib/python2.7/<a href="http://hg.python.org/cpython/file/2.7/Lib/socket.py#l553">socket.py</a>", line 553, in create_connection
+File "D:\cygwin\home\user\buildarea\3.x-windows\build\lib\test\test_logging.py", line 3599, in test_rollover
+File "D:\cygwin\home\user\buildarea\3.x-windows\build\lib\<a href="http://hg.python.org/cpython/file/default/Lib/test/test_logging.py#l3599">test\test_logging.py</a>", line 3599, in test_rollover
+File "/export/home/buildbot/32bits/3.x-indiana-x86/build/Lib/sysconfig.py", line 436, in get_path
+File "/export/home/buildbot/32bits/3.x-indiana-x86/build/Lib/<a href="http://hg.python.org/cpython/file/default/Lib/sysconfig.py#l436">sysconfig.py</a>", line 436, in get_path
+File "/Users/user/src/python-svn/Lib/test/test_codecs.py", line 531, in
+File "/Users/user/src/python-svn/Lib/<a href="http://hg.python.org/cpython/file/default/Lib/test/test_codecs.py#l531">test/test_codecs.py</a>", line 531, in
+File "/home/user/code/src/cpython/python/Lib/shutil.py", line 98, in copyfile
+File "/home/user/code/src/cpython/python/Lib/<a href="http://hg.python.org/cpython/file/default/Lib/shutil.py#l98">shutil.py</a>", line 98, in copyfile
+File "/srv/buildbot/buildarea/3.1-ubuntu/build/Lib/distutils/spawn.py", line 138, in _spawn_posix
+File "/srv/buildbot/buildarea/3.1-ubuntu/build/Lib/<a href="http://hg.python.org/cpython/file/3.1/Lib/distutils/spawn.py#l138">distutils/spawn.py</a>", line 138, in _spawn_posix
+File "D:\Buildslave\3.x-windows\build\lib\test\test_urllib2_localnet.py", line 364, in urlopen
+File "D:\Buildslave\3.x-windows\build\lib\<a href="http://hg.python.org/cpython/file/default/Lib/test/test_urllib2_localnet.py#l364">test\test_urllib2_localnet.py</a>", line 364, in urlopen
+File "D:\Buildslave\3.x-windows\build\lib\urllib\request.py", line 1116, in do_open
+File "D:\Buildslave\3.x-windows\build\lib\<a href="http://hg.python.org/cpython/file/default/Lib/urllib/request.py#l1116">urllib\request.py</a>", line 1116, in do_open
+File "/var/lib/buildslave/3.x-gentoo/build/Lib/socketserver.py", line 713, in finish
+File "/var/lib/buildslave/3.x-gentoo/build/Lib/<a href="http://hg.python.org/cpython/file/default/Lib/socketserver.py#l713">socketserver.py</a>", line 713, in finish
+File "/home/user/cpython/Lib/test/support.py", line 217, in make_legacy_pyc
+File "/home/user/cpython/Lib/<a href="http://hg.python.org/cpython/file/default/Lib/test/support.py#l217">test/support.py</a>", line 217, in make_legacy_pyc
+File "/home/buildbot/buildarea/3.x-fedora/build/Lib/importlib/_bootstrap.py", line 342, in _load_module
+File "/home/buildbot/buildarea/3.x-fedora/build/Lib/<a href="http://hg.python.org/cpython/file/default/Lib/importlib/_bootstrap.py#l342">importlib/_bootstrap.py</a>", line 342, in _load_module
+File "/Users/buildbot/buildarea/custom-tiger-1/build/Lib/subprocess.py", line 1531, in wait
+File "/Users/buildbot/buildarea/custom-tiger-1/build/Lib/<a href="http://hg.python.org/cpython/file/default/Lib/subprocess.py#l1531">subprocess.py</a>", line 1531, in wait
+File "/sw/lib/python3.1/subprocess.py", line 719, in communicate
+File "/sw/lib/python3.1/<a href="http://hg.python.org/cpython/file/3.1/Lib/subprocess.py#l719">subprocess.py</a>", line 719, in communicate
+File "c:\Python26\lib\traceback.py", line 57, in print_tb
+File "c:\Python26\lib\<a href="http://hg.python.org/cpython/file/2.6/Lib/traceback.py#l57">traceback.py</a>", line 57, in print_tb
+File "C:\Programme\Python26\lib\logging\handlers.py", line 76, in emit
+File "C:\Programme\Python26\lib\<a href="http://hg.python.org/cpython/file/2.6/Lib/logging/handlers.py#l76">logging\handlers.py</a>", line 76, in emit
+File "C:\www\Python27\lib\subprocess.py", line 486, in call return Popen
+File "C:\www\Python27\lib\<a href="http://hg.python.org/cpython/file/2.7/Lib/subprocess.py#l486">subprocess.py</a>", line 486, in call return Popen
+File "C:\www\Python2.7\lib\subprocess.py", line 486, in call return Popen
+File "C:\www\Python2.7\lib\<a href="http://hg.python.org/cpython/file/2.7/Lib/subprocess.py#l486">subprocess.py</a>", line 486, in call return Popen
+##
+## tracebacks - these lines are not linkified because they are not files in Lib/*:
+File "C:\Python31\lib\site-packages\unittest2\main.py", line 237, in main_
+File "C:\Python31\lib\site-packages\unittest2\main.py", line 237, in main_
+File "/usr/lib/python2.5/site-packages/mp-2.6.2.1-py2.5-cygwin-1.7.1-i686.egg/multiprocessing/queues.py", line 91, in get_path
+File "/usr/lib/python2.5/site-packages/mp-2.6.2.1-py2.5-cygwin-1.7.1-i686.egg/multiprocessing/queues.py", line 91, in get_path
+File "build/build.py", line 173, in runCmd subprocess.call(cmd)
+File "build/build.py", line 173, in runCmd subprocess.call(cmd)
+##
 ## issues - the lowest issue id on bugs.python.org is #1000, the highest is #1779871
  #1
  #1

tests/test_python_tracker.py

+
 import sys
 import unittest
 import os.path
 
 import wikify
 
-# --- configure rules
+
+# --- configure wikification rules ---
+
+# --- replacement functions
+def make_file_link(match):
+    baseurl = 'http://hg.python.org/cpython/file/default/'
+    sep = match.group('sep')
+    path = match.group('path')
+    npath = path.replace('\\', '/')  # normalize the path separators
+    lnum = match.group('lnum') or ''  # the match includes the ':'
+    if not npath.endswith('/'):
+        # files without and with line number
+        if not lnum:
+            return '<a href="%s%s">%s%s</a>' % (baseurl, npath, sep, path)
+        else:
+            return '<a href="%s%s#l%s">%s%s%s</a>' % (baseurl, npath, lnum[1:],
+                                                      sep, path, lnum)
+    else:
+        # dirs
+        return '<a href="%s%s">%s%s</a>%s' % (baseurl, npath, sep, 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 'default'
+    version = match.group(1)
+    if '.' not in version:
+        version = '.'.join(version)
+    if version in ['2.5', '2.6', '2.7', '3.1', '3.2', '3.3']:
+        return version
+    return 'default'
+
+def make_traceback_link(match):
+    """Convert the file/line in the traceback lines in a link."""
+    baseurl = 'http://hg.python.org/cpython/file/'
+    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)
+# --/ replacement functions
+
 substitutions = [
     # URLs (adapted from Roundup)
     # replacement does not escape HTML chars
-    (r'''(?x)\b
+    (r'''(?xi)\b
          (
           (ht|f)tp(s?)://                   # protocol
           ([\w]+(:\w+)?@)?                  # username/password
     (r'\b(?P<revstr>r\.?(ev\.?(ision)?)?\s*)(?P<revision>\d{4,})',
      r'<a href="http://hg.python.org/lookup/r\4">\1\4</a>'),
 
+    # Lib/somefile.py, Lib/somefile.py:123, Modules/somemodule.c:123, ...
+    (r'(?P<sep>(?<!\w/)|(?<!\w)/)\b(?P<path>(?:Demo|Doc|Grammar|'
+     r'Include|Lib|Mac|Misc|Modules|Parser|PC|PCbuild|Python|'
+     r'RISCOS|Tools|Objects)/[-.\w/]+[a-zA-Z0-9]/?)(?P<lnum>:\d{1,5})?',
+     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
+    (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, ...
+    (r'(?i)\b(?<![/=-])PEP\s*(\d{1,4})(?!/)\b', make_pep_link),
+
     # devguide
     (r'\bdevguide(/\w+(\.html)?(#[\w-]+)?)?',
      r'<a href="http://docs.python.org/\0">\0</a>'),
 ]
 
+rules = [wikify.create_regexp_rule(a,b) for a,b in substitutions]
 
-rules = [wikify.create_regexp_rule(a,b) for a,b in substitutions]
+# --/ configure wikification rules ---
+
 
 class TestBugsPythonOrgData(unittest.TestCase):
     def test_replacement(self):
 0.1  - proof of concept, production ready, no API sugar
        and optimizations
 0.2  - helper to build regexp based rules
+0.3  - allow callables in replacements for regexp rules
 """
 
 __author__ = "anatoly techtonik <techtonik@gmail.com>"
 __license__ = "Public Domain"
-__version__ = "0.2"
+__version__ = "0.3"
 
 
 # --- define rules ---
 # helper to build regexp based rules
 def create_regexp_rule(search, replace=r'\0'):
   """ helper that returns rule, suitable as an argument to
-      wikify. parameters are regexps - what to `search` for
-      and what to `replace` with. it is possible to use
-      backreferences (like \1) in replacement string.
+      wikify. `search` is regexp, and `replace` is either
+      string with backreferences (like \0, \1 etc.) or a
+      callable that receives `re.MatchObject`.
   """
   search = re.compile(search)
 
       if match == None:
         return None
 
-      # match.groups() doesn't return whole match as a 1st element
-      groups = (match.group(0),) + match.groups()
-      replaced = subst_backrefs(_replace, groups)
+      if callable(_replace):
+        replaced = _replace(match)
+      else:
+        # match.groups() doesn't return whole match as a 1st element
+        groups = (match.group(0),) + match.groups()
+        replaced = subst_backrefs(_replace, groups)
 
       return (text[:match.start()], replaced, text[match.end():])