summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/howto/advocacy.rst2
-rw-r--r--Doc/howto/curses.rst2
-rw-r--r--Doc/howto/regex.rst2
-rw-r--r--Doc/howto/unicode.rst2
-rw-r--r--Doc/library/curses.rst4
-rw-r--r--Doc/library/re.rst3
-rw-r--r--Lib/DocXMLRPCServer.py4
-rw-r--r--Lib/_abcoll.py1
-rw-r--r--Lib/distutils/sysconfig.py8
-rwxr-xr-xLib/pydoc.py2
-rw-r--r--Lib/re.py2
-rw-r--r--Lib/tarfile.py18
-rw-r--r--Lib/test/output/test_profile97
-rw-r--r--Lib/test/profilee.py115
-rw-r--r--Lib/test/test_docxmlrpc.py6
-rwxr-xr-x[-rw-r--r--]Lib/test/test_profile.py284
-rw-r--r--Lib/test/test_sys.py9
-rw-r--r--Lib/test/test_trace.py61
-rw-r--r--Lib/test/test_wave.py61
-rw-r--r--Misc/python-mode.el544
-rw-r--r--Objects/classobject.c24
-rw-r--r--Objects/dictobject.c16
-rw-r--r--Objects/frameobject.c7
-rw-r--r--Objects/listobject.c24
-rw-r--r--Objects/methodobject.c22
-rw-r--r--Objects/setobject.c22
-rw-r--r--Objects/tupleobject.c58
-rw-r--r--Objects/unicodeobject.c36
-rw-r--r--Python/compile.c28
29 files changed, 905 insertions, 559 deletions
diff --git a/Doc/howto/advocacy.rst b/Doc/howto/advocacy.rst
index 7d7706e..669ce72 100644
--- a/Doc/howto/advocacy.rst
+++ b/Doc/howto/advocacy.rst
@@ -265,7 +265,7 @@ the organizations that use Python.
**What are the restrictions on Python's use?**
They're practically nonexistent. Consult the :file:`Misc/COPYRIGHT` file in the
-source distribution, or http://www.python.org/doc/Copyright.html for the full
+source distribution, or the section :ref:`history-and-license` for the full
language, but it boils down to three conditions.
* You have to leave the copyright notice on the software; if you don't include
diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst
index 12fb936..841a030 100644
--- a/Doc/howto/curses.rst
+++ b/Doc/howto/curses.rst
@@ -1,3 +1,5 @@
+.. _curses-howto:
+
**********************************
Curses Programming with Python
**********************************
diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst
index 794c945..406ce1c 100644
--- a/Doc/howto/regex.rst
+++ b/Doc/howto/regex.rst
@@ -1,3 +1,5 @@
+.. _regex-howto:
+
****************************
Regular Expression HOWTO
****************************
diff --git a/Doc/howto/unicode.rst b/Doc/howto/unicode.rst
index 40c77d6..67aa2b2 100644
--- a/Doc/howto/unicode.rst
+++ b/Doc/howto/unicode.rst
@@ -276,7 +276,7 @@ Unicode result). The following examples show the differences::
Encodings are specified as strings containing the encoding's name. Python
comes with roughly 100 different encodings; see the Python Library Reference at
-<http://docs.python.org/lib/standard-encodings.html> for a list. Some encodings
+:ref:`standard-encodings` for a list. Some encodings
have multiple names; for example, 'latin-1', 'iso_8859_1' and '8859' are all
synonyms for the same encoding.
diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst
index 7f82bca..4135182 100644
--- a/Doc/library/curses.rst
+++ b/Doc/library/curses.rst
@@ -45,9 +45,9 @@ Linux and the BSD variants of Unix.
Convenience function to ensure proper terminal setup and resetting on
application entry and exit.
- `Curses Programming with Python <http://www.python.org/doc/howto/curses/curses.html>`_
+ :ref:`curses-howto`
Tutorial material on using curses with Python, by Andrew Kuchling and Eric
- Raymond, is available on the Python Web site.
+ Raymond.
The :file:`Demo/curses/` directory in the Python source distribution contains
some example programs using the curses bindings provided by this module.
diff --git a/Doc/library/re.rst b/Doc/library/re.rst
index 5c2935b..0c64c72 100644
--- a/Doc/library/re.rst
+++ b/Doc/library/re.rst
@@ -65,8 +65,7 @@ and implementation of regular expressions, consult the Friedl book referenced
above, or almost any textbook about compiler construction.
A brief explanation of the format of regular expressions follows. For further
-information and a gentler presentation, consult the Regular Expression HOWTO,
-accessible from http://www.python.org/doc/howto/.
+information and a gentler presentation, consult the :ref:`regex-howto`.
Regular expressions can contain both special and ordinary characters. Most
ordinary characters, like ``'A'``, ``'a'``, or ``'0'``, are the simplest regular
diff --git a/Lib/DocXMLRPCServer.py b/Lib/DocXMLRPCServer.py
index 504b669..246fd74 100644
--- a/Lib/DocXMLRPCServer.py
+++ b/Lib/DocXMLRPCServer.py
@@ -30,7 +30,7 @@ class ServerHTMLDoc(pydoc.HTMLDoc):
results = []
here = 0
- # XXX Note that this regular expressions does not allow for the
+ # XXX Note that this regular expression does not allow for the
# hyperlinking of arbitrary strings being used as method
# names. Only methods with names consisting of word characters
# and '.'s are hyperlinked.
@@ -52,7 +52,7 @@ class ServerHTMLDoc(pydoc.HTMLDoc):
url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
results.append('<a href="%s">%s</a>' % (url, escape(all)))
elif pep:
- url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
+ url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
results.append('<a href="%s">%s</a>' % (url, escape(all)))
elif text[end:end+1] == '(':
results.append(self.namelink(name, methods, funcs, classes))
diff --git a/Lib/_abcoll.py b/Lib/_abcoll.py
index ba084aa..90a78cb 100644
--- a/Lib/_abcoll.py
+++ b/Lib/_abcoll.py
@@ -385,6 +385,7 @@ class Mapping(metaclass=ABCMeta):
def __ne__(self, other):
return not (self == other)
+
class MappingView(metaclass=ABCMeta):
def __init__(self, mapping):
diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py
index 4d790cc..39216a5 100644
--- a/Lib/distutils/sysconfig.py
+++ b/Lib/distutils/sysconfig.py
@@ -37,8 +37,12 @@ if os.name == "nt" and "\\pc\\v" in project_base[-10:].lower():
# different (hard-wired) directories.
# Setup.local is available for Makefile builds including VPATH builds,
# Setup.dist is available on Windows
-python_build = any(os.path.isfile(os.path.join(project_base, "Modules", fn))
- for fn in ("Setup.dist", "Setup.local"))
+def _python_build():
+ for fn in ("Setup.dist", "Setup.local"):
+ if os.path.isfile(os.path.join(project_base, "Modules", fn)):
+ return True
+ return False
+python_build = _python_build()
def get_python_version():
"""Return a string containing the major and minor Python version,
diff --git a/Lib/pydoc.py b/Lib/pydoc.py
index de8d193..c6ec68e 100755
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -536,7 +536,7 @@ class HTMLDoc(Doc):
url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
results.append('<a href="%s">%s</a>' % (url, escape(all)))
elif pep:
- url = 'http://www.python.org/peps/pep-%04d' % int(pep)
+ url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
results.append('<a href="%s">%s</a>' % (url, escape(all)))
elif text[end:end+1] == '(':
results.append(self.namelink(name, methods, funcs, classes))
diff --git a/Lib/re.py b/Lib/re.py
index 962c2d7..32737b7 100644
--- a/Lib/re.py
+++ b/Lib/re.py
@@ -294,8 +294,8 @@ class Scanner:
p.append(sre_parse.SubPattern(s, [
(SUBPATTERN, (len(p)+1, sre_parse.parse(phrase, flags))),
]))
+ s.groups = len(p)+1
p = sre_parse.SubPattern(s, [(BRANCH, (None, p))])
- s.groups = len(p)
self.scanner = sre_compile.compile(p)
def scan(self, string):
result = []
diff --git a/Lib/tarfile.py b/Lib/tarfile.py
index b184ed8..b789cca 100644
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -2005,15 +2005,11 @@ class TarFile(object):
for tarinfo in members:
if tarinfo.isdir():
- # Extract directory with a safe mode, so that
- # all files below can be extracted as well.
- try:
- os.makedirs(os.path.join(path, tarinfo.name), 0o700)
- except EnvironmentError:
- pass
+ # Extract directories with a safe mode.
directories.append(tarinfo)
- else:
- self.extract(tarinfo, path)
+ tarinfo = copy.copy(tarinfo)
+ tarinfo.mode = 0o700
+ self.extract(tarinfo, path)
# Reverse sort directories.
directories.sort(key=lambda a: a.name)
@@ -2118,6 +2114,8 @@ class TarFile(object):
# Create all upper directories.
upperdirs = os.path.dirname(targetpath)
if upperdirs and not os.path.exists(upperdirs):
+ # Create directories that are not part of the archive with
+ # default permissions.
os.makedirs(upperdirs)
if tarinfo.islnk() or tarinfo.issym():
@@ -2154,7 +2152,9 @@ class TarFile(object):
"""Make a directory called targetpath.
"""
try:
- os.mkdir(targetpath)
+ # Use a safe mode for the directory, the real mode is set
+ # later in _extract_member().
+ os.mkdir(targetpath, 0o700)
except EnvironmentError as e:
if e.errno != errno.EEXIST:
raise
diff --git a/Lib/test/output/test_profile b/Lib/test/output/test_profile
deleted file mode 100644
index 0582611..0000000
--- a/Lib/test/output/test_profile
+++ /dev/null
@@ -1,97 +0,0 @@
-test_profile
- 125 function calls (105 primitive calls) in 1.000 CPU seconds
-
- Ordered by: standard name
-
- ncalls tottime percall cumtime percall filename:lineno(function)
- 4 0.000 0.000 0.000 0.000 :0(append)
- 4 0.000 0.000 0.000 0.000 :0(exc_info)
- 1 0.000 0.000 1.000 1.000 :0(exec)
- 12 0.000 0.000 0.012 0.001 :0(hasattr)
- 1 0.000 0.000 0.000 0.000 :0(setprofile)
- 1 0.000 0.000 1.000 1.000 <string>:1(<module>)
- 2 0.000 0.000 0.000 0.000 io.py:1213(flush)
- 1 0.000 0.000 0.000 0.000 io.py:269(flush)
- 1 0.000 0.000 0.000 0.000 io.py:656(closed)
- 1 0.000 0.000 0.000 0.000 io.py:874(flush)
- 0 0.000 0.000 profile:0(profiler)
- 1 0.000 0.000 1.000 1.000 profile:0(testfunc())
- 8 0.064 0.008 0.080 0.010 test_profile.py:103(subhelper)
- 28 0.028 0.001 0.028 0.001 test_profile.py:115(__getattr__)
- 1 0.270 0.270 1.000 1.000 test_profile.py:30(testfunc)
- 23/3 0.150 0.007 0.170 0.057 test_profile.py:40(factorial)
- 20 0.020 0.001 0.020 0.001 test_profile.py:53(mul)
- 2 0.040 0.020 0.600 0.300 test_profile.py:60(helper)
- 4 0.116 0.029 0.120 0.030 test_profile.py:78(helper1)
- 2 0.000 0.000 0.140 0.070 test_profile.py:89(helper2_indirect)
- 8 0.312 0.039 0.400 0.050 test_profile.py:93(helper2)
-
-
- Ordered by: standard name
-
-Function called...
-:0(append) ->
-:0(exc_info) ->
-:0(exec) -> <string>:1(<module>)(1) 1.000
- io.py:1213(flush)(2) 0.000
-:0(hasattr) -> test_profile.py:115(__getattr__)(12) 0.028
-:0(setprofile) ->
-<string>:1(<module>) -> test_profile.py:30(testfunc)(1) 1.000
-io.py:1213(flush) -> io.py:269(flush)(1) 0.000
- io.py:874(flush)(1) 0.000
-io.py:269(flush) ->
-io.py:656(closed) ->
-io.py:874(flush) -> io.py:656(closed)(1) 0.000
-profile:0(profiler) -> profile:0(testfunc())(1) 1.000
-profile:0(testfunc()) -> :0(exec)(1) 1.000
- :0(setprofile)(1) 0.000
-test_profile.py:103(subhelper) -> test_profile.py:115(__getattr__)(16) 0.028
-test_profile.py:115(__getattr__) ->
-test_profile.py:30(testfunc) -> test_profile.py:40(factorial)(1) 0.170
- test_profile.py:60(helper)(2) 0.600
-test_profile.py:40(factorial) -> test_profile.py:40(factorial)(20) 0.170
- test_profile.py:53(mul)(20) 0.020
-test_profile.py:53(mul) ->
-test_profile.py:60(helper) -> test_profile.py:78(helper1)(4) 0.120
- test_profile.py:89(helper2_indirect)(2) 0.140
- test_profile.py:93(helper2)(6) 0.400
-test_profile.py:78(helper1) -> :0(append)(4) 0.000
- :0(exc_info)(4) 0.000
- :0(hasattr)(4) 0.012
-test_profile.py:89(helper2_indirect) -> test_profile.py:40(factorial)(2) 0.170
- test_profile.py:93(helper2)(2) 0.400
-test_profile.py:93(helper2) -> :0(hasattr)(8) 0.012
- test_profile.py:103(subhelper)(8) 0.080
-
-
- Ordered by: standard name
-
-Function was called by...
-:0(append) <- test_profile.py:78(helper1)(4) 0.120
-:0(exc_info) <- test_profile.py:78(helper1)(4) 0.120
-:0(exec) <- profile:0(testfunc())(1) 1.000
-:0(hasattr) <- test_profile.py:78(helper1)(4) 0.120
- test_profile.py:93(helper2)(8) 0.400
-:0(setprofile) <- profile:0(testfunc())(1) 1.000
-<string>:1(<module>) <- :0(exec)(1) 1.000
-io.py:1213(flush) <- :0(exec)(2) 1.000
-io.py:269(flush) <- io.py:1213(flush)(1) 0.000
-io.py:656(closed) <- io.py:874(flush)(1) 0.000
-io.py:874(flush) <- io.py:1213(flush)(1) 0.000
-profile:0(profiler) <-
-profile:0(testfunc()) <- profile:0(profiler)(1) 0.000
-test_profile.py:103(subhelper) <- test_profile.py:93(helper2)(8) 0.400
-test_profile.py:115(__getattr__) <- :0(hasattr)(12) 0.012
- test_profile.py:103(subhelper)(16) 0.080
-test_profile.py:30(testfunc) <- <string>:1(<module>)(1) 1.000
-test_profile.py:40(factorial) <- test_profile.py:30(testfunc)(1) 1.000
- test_profile.py:40(factorial)(20) 0.170
- test_profile.py:89(helper2_indirect)(2) 0.140
-test_profile.py:53(mul) <- test_profile.py:40(factorial)(20) 0.170
-test_profile.py:60(helper) <- test_profile.py:30(testfunc)(2) 1.000
-test_profile.py:78(helper1) <- test_profile.py:60(helper)(4) 0.600
-test_profile.py:89(helper2_indirect) <- test_profile.py:60(helper)(2) 0.600
-test_profile.py:93(helper2) <- test_profile.py:60(helper)(6) 0.600
- test_profile.py:89(helper2_indirect)(2) 0.140
-
-
diff --git a/Lib/test/profilee.py b/Lib/test/profilee.py
new file mode 100644
index 0000000..6ad2c83
--- /dev/null
+++ b/Lib/test/profilee.py
@@ -0,0 +1,115 @@
+"""
+Input for test_profile.py and test_cprofile.py.
+
+IMPORTANT: This stuff is touchy. If you modify anything above the
+test class you'll have to regenerate the stats by running the two
+test files.
+
+*ALL* NUMBERS in the expected output are relevant. If you change
+the formatting of pstats, please don't just regenerate the expected
+output without checking very carefully that not a single number has
+changed.
+"""
+
+import sys
+
+# In order to have reproducible time, we simulate a timer in the global
+# variable 'TICKS', which represents simulated time in milliseconds.
+# (We can't use a helper function increment the timer since it would be
+# included in the profile and would appear to consume all the time.)
+TICKS = 42000
+
+def timer():
+ return TICKS
+
+def testfunc():
+ # 1 call
+ # 1000 ticks total: 270 ticks local, 730 ticks in subfunctions
+ global TICKS
+ TICKS += 99
+ helper() # 300
+ helper() # 300
+ TICKS += 171
+ factorial(14) # 130
+
+def factorial(n):
+ # 23 calls total
+ # 170 ticks total, 150 ticks local
+ # 3 primitive calls, 130, 20 and 20 ticks total
+ # including 116, 17, 17 ticks local
+ global TICKS
+ if n > 0:
+ TICKS += n
+ return mul(n, factorial(n-1))
+ else:
+ TICKS += 11
+ return 1
+
+def mul(a, b):
+ # 20 calls
+ # 1 tick, local
+ global TICKS
+ TICKS += 1
+ return a * b
+
+def helper():
+ # 2 calls
+ # 300 ticks total: 20 ticks local, 260 ticks in subfunctions
+ global TICKS
+ TICKS += 1
+ helper1() # 30
+ TICKS += 2
+ helper1() # 30
+ TICKS += 6
+ helper2() # 50
+ TICKS += 3
+ helper2() # 50
+ TICKS += 2
+ helper2() # 50
+ TICKS += 5
+ helper2_indirect() # 70
+ TICKS += 1
+
+def helper1():
+ # 4 calls
+ # 30 ticks total: 29 ticks local, 1 tick in subfunctions
+ global TICKS
+ TICKS += 10
+ hasattr(C(), "foo") # 1
+ TICKS += 19
+ lst = []
+ lst.append(42) # 0
+ sys.exc_info() # 0
+
+def helper2_indirect():
+ helper2() # 50
+ factorial(3) # 20
+
+def helper2():
+ # 8 calls
+ # 50 ticks local: 39 ticks local, 11 ticks in subfunctions
+ global TICKS
+ TICKS += 11
+ hasattr(C(), "bar") # 1
+ TICKS += 13
+ subhelper() # 10
+ TICKS += 15
+
+def subhelper():
+ # 8 calls
+ # 10 ticks total: 8 ticks local, 2 ticks in subfunctions
+ global TICKS
+ TICKS += 2
+ for i in range(2): # 0
+ try:
+ C().foo # 1 x 2
+ except AttributeError:
+ TICKS += 3 # 3 x 2
+
+class C:
+ def __getattr__(self, name):
+ # 28 calls
+ # 1 tick, local
+ global TICKS
+ TICKS += 1
+ raise AttributeError
diff --git a/Lib/test/test_docxmlrpc.py b/Lib/test/test_docxmlrpc.py
index 1a056f8..c9984b3 100644
--- a/Lib/test/test_docxmlrpc.py
+++ b/Lib/test/test_docxmlrpc.py
@@ -117,11 +117,11 @@ b"""<dl><dt><a name="-&lt;lambda&gt;"><strong>&lt;lambda&gt;</strong></a>(x, y)<
The documentation for the "add" method contains the test material.
"""
self.client.request("GET", "/")
- response = self.client.getresponse()
+ response = self.client.getresponse().read()
self.assert_( # This is ugly ... how can it be made better?
-b"""<dl><dt><a name="-add"><strong>add</strong></a>(x, y)</dt><dd><tt>Add&nbsp;two&nbsp;instances&nbsp;together.&nbsp;This&nbsp;follows&nbsp;<a href="http://www.python.org/peps/pep-0008.html">PEP008</a>,&nbsp;but&nbsp;has&nbsp;nothing<br>\nto&nbsp;do&nbsp;with&nbsp;<a href="http://www.rfc-editor.org/rfc/rfc1952.txt">RFC1952</a>.&nbsp;Case&nbsp;should&nbsp;matter:&nbsp;pEp008&nbsp;and&nbsp;rFC1952.&nbsp;&nbsp;Things<br>\nthat&nbsp;start&nbsp;with&nbsp;http&nbsp;and&nbsp;ftp&nbsp;should&nbsp;be&nbsp;auto-linked,&nbsp;too:<br>\n<a href="http://google.com">http://google.com</a>.</tt></dd></dl>"""
- in response.read())
+b"""<dl><dt><a name="-add"><strong>add</strong></a>(x, y)</dt><dd><tt>Add&nbsp;two&nbsp;instances&nbsp;together.&nbsp;This&nbsp;follows&nbsp;<a href="http://www.python.org/dev/peps/pep-0008/">PEP008</a>,&nbsp;but&nbsp;has&nbsp;nothing<br>\nto&nbsp;do&nbsp;with&nbsp;<a href="http://www.rfc-editor.org/rfc/rfc1952.txt">RFC1952</a>.&nbsp;Case&nbsp;should&nbsp;matter:&nbsp;pEp008&nbsp;and&nbsp;rFC1952.&nbsp;&nbsp;Things<br>\nthat&nbsp;start&nbsp;with&nbsp;http&nbsp;and&nbsp;ftp&nbsp;should&nbsp;be&nbsp;auto-linked,&nbsp;too:<br>\n<a href="http://google.com">http://google.com</a>.</tt></dd></dl>"""
+ in response, response)
def test_system_methods(self):
"""Test the precense of three consecutive system.* methods.
diff --git a/Lib/test/test_profile.py b/Lib/test/test_profile.py
index 95ad8d2..632911d 100644..100755
--- a/Lib/test/test_profile.py
+++ b/Lib/test/test_profile.py
@@ -1,123 +1,179 @@
"""Test suite for the profile module."""
-import profile, pstats, sys
+import os
+import sys
+import pstats
+import unittest
+from difflib import unified_diff
+from io import StringIO
+from test.test_support import run_unittest
-# In order to have reproducible time, we simulate a timer in the global
-# variable 'ticks', which represents simulated time in milliseconds.
-# (We can't use a helper function increment the timer since it would be
-# included in the profile and would appear to consume all the time.)
-ticks = 0
+import profile
+from test.profilee import testfunc, timer
+
+
+class ProfileTest(unittest.TestCase):
+
+ profilerclass = profile.Profile
+ methodnames = ['print_stats', 'print_callers', 'print_callees']
+ expected_output = {}
+
+ @classmethod
+ def do_profiling(cls):
+ results = []
+ prof = cls.profilerclass(timer, 0.001)
+ prof.runctx("testfunc()", globals(), locals())
+ results.append(timer())
+ for methodname in cls.methodnames:
+ s = StringIO()
+ stats = pstats.Stats(prof, stream=s)
+ stats.strip_dirs().sort_stats("stdname")
+ getattr(stats, methodname)()
+ results.append(s.getvalue())
+ return results
+
+ def test_cprofile(self):
+ results = self.do_profiling()
+ self.assertEqual(results[0], 43000)
+ for i, method in enumerate(self.methodnames):
+ if results[i+1] != self.expected_output[method]:
+ print("Stats.%s output for %s doesn't fit expectation!" %
+ (method, self.profilerclass.__name__))
+ print('\n'.join(unified_diff(
+ results[i+1].split('\n'),
+ self.expected_output[method].split('\n'))))
+
+
+def regenerate_expected_output(filename, cls):
+ filename = filename.rstrip('co')
+ print('Regenerating %s...' % filename)
+ results = cls.do_profiling()
+
+ newfile = []
+ with open(filename, 'r') as f:
+ for line in f:
+ newfile.append(line)
+ if line[:6] == '#--cut':
+ break
+
+ with open(filename, 'w') as f:
+ f.writelines(newfile)
+ for i, method in enumerate(cls.methodnames):
+ f.write('%s.expected_output[%r] = """\\\n%s"""\n' % (
+ cls.__name__, method, results[i+1]))
+ f.write('\nif __name__ == "__main__":\n main()\n')
-# IMPORTANT: this is an output test. *ALL* NUMBERS in the expected
-# output are relevant. If you change the formatting of pstats,
-# please don't just regenerate output/test_profile without checking
-# very carefully that not a single number has changed.
def test_main():
- global ticks
- ticks = 42000
- prof = profile.Profile(timer)
- prof.runctx("testfunc()", globals(), locals())
- assert ticks == 43000, ticks
- st = pstats.Stats(prof)
- st.strip_dirs().sort_stats('stdname').print_stats()
- st.print_callees()
- st.print_callers()
-
-def timer():
- return ticks*0.001
-
-def testfunc():
- # 1 call
- # 1000 ticks total: 270 ticks local, 730 ticks in subfunctions
- global ticks
- ticks += 99
- helper() # 300
- helper() # 300
- ticks += 171
- factorial(14) # 130
-
-def factorial(n):
- # 23 calls total
- # 170 ticks total, 150 ticks local
- # 3 primitive calls, 130, 20 and 20 ticks total
- # including 116, 17, 17 ticks local
- global ticks
- if n > 0:
- ticks += n
- return mul(n, factorial(n-1))
+ run_unittest(ProfileTest)
+
+def main():
+ if '-r' not in sys.argv:
+ test_main()
else:
- ticks += 11
- return 1
-
-def mul(a, b):
- # 20 calls
- # 1 tick, local
- global ticks
- ticks += 1
- return a * b
-
-def helper():
- # 2 calls
- # 300 ticks total: 20 ticks local, 260 ticks in subfunctions
- global ticks
- ticks += 1
- helper1() # 30
- ticks += 2
- helper1() # 30
- ticks += 6
- helper2() # 50
- ticks += 3
- helper2() # 50
- ticks += 2
- helper2() # 50
- ticks += 5
- helper2_indirect() # 70
- ticks += 1
-
-def helper1():
- # 4 calls
- # 30 ticks total: 29 ticks local, 1 tick in subfunctions
- global ticks
- ticks += 10
- hasattr(C(), "foo") # 1
- ticks += 19
- lst = []
- lst.append(42) # 0
- sys.exc_info() # 0
-
-def helper2_indirect():
- helper2() # 50
- factorial(3) # 20
-
-def helper2():
- # 8 calls
- # 50 ticks local: 39 ticks local, 11 ticks in subfunctions
- global ticks
- ticks += 11
- hasattr(C(), "bar") # 1
- ticks += 13
- subhelper() # 10
- ticks += 15
-
-def subhelper():
- # 8 calls
- # 10 ticks total: 8 ticks local, 2 ticks in subfunctions
- global ticks
- ticks += 2
- for i in range(2): # 0
- try:
- C().foo # 1 x 2
- except AttributeError:
- ticks += 3 # 3 x 2
-
-class C:
- def __getattr__(self, name):
- # 28 calls
- # 1 tick, local
- global ticks
- ticks += 1
- raise AttributeError
+ regenerate_expected_output(__file__, ProfileTest)
+
+
+# Don't remove this comment. Everything below it is auto-generated.
+#--cut--------------------------------------------------------------------------
+ProfileTest.expected_output['print_stats'] = """\
+ 126 function calls (106 primitive calls) in 999.751 CPU seconds
+
+ Ordered by: standard name
+
+ ncalls tottime percall cumtime percall filename:lineno(function)
+ 4 -0.004 -0.001 -0.004 -0.001 :0(append)
+ 4 -0.004 -0.001 -0.004 -0.001 :0(exc_info)
+ 1 -0.004 -0.004 999.753 999.753 :0(exec)
+ 12 -0.024 -0.002 11.964 0.997 :0(hasattr)
+ 1 0.000 0.000 0.000 0.000 :0(setprofile)
+ 1 -0.002 -0.002 999.767 999.767 <string>:1(<module>)
+ 2 -0.004 -0.002 -0.010 -0.005 io.py:1213(flush)
+ 2 -0.002 -0.001 -0.002 -0.001 io.py:656(closed)
+ 2 -0.004 -0.002 -0.006 -0.003 io.py:874(flush)
+ 0 0.000 0.000 profile:0(profiler)
+ 1 -0.002 -0.002 999.751 999.751 profile:0(testfunc())
+ 28 27.972 0.999 27.972 0.999 profilee.py:110(__getattr__)
+ 1 269.996 269.996 999.769 999.769 profilee.py:25(testfunc)
+ 23/3 149.937 6.519 169.917 56.639 profilee.py:35(factorial)
+ 20 19.980 0.999 19.980 0.999 profilee.py:48(mul)
+ 2 39.986 19.993 599.830 299.915 profilee.py:55(helper)
+ 4 115.984 28.996 119.964 29.991 profilee.py:73(helper1)
+ 2 -0.006 -0.003 139.946 69.973 profilee.py:84(helper2_indirect)
+ 8 311.976 38.997 399.912 49.989 profilee.py:88(helper2)
+ 8 63.976 7.997 79.960 9.995 profilee.py:98(subhelper)
+
+
+"""
+ProfileTest.expected_output['print_callers'] = """\
+ Ordered by: standard name
+
+Function was called by...
+:0(append) <- profilee.py:73(helper1)(4) 119.964
+:0(exc_info) <- profilee.py:73(helper1)(4) 119.964
+:0(exec) <- profile:0(testfunc())(1) 999.751
+:0(hasattr) <- profilee.py:73(helper1)(4) 119.964
+ profilee.py:88(helper2)(8) 399.912
+:0(setprofile) <- profile:0(testfunc())(1) 999.751
+<string>:1(<module>) <- :0(exec)(1) 999.753
+io.py:1213(flush) <- :0(exec)(2) 999.753
+io.py:656(closed) <- io.py:874(flush)(2) -0.006
+io.py:874(flush) <- io.py:1213(flush)(2) -0.010
+profile:0(profiler) <-
+profile:0(testfunc()) <- profile:0(profiler)(1) 0.000
+profilee.py:110(__getattr__) <- :0(hasattr)(12) 11.964
+ profilee.py:98(subhelper)(16) 79.960
+profilee.py:25(testfunc) <- <string>:1(<module>)(1) 999.767
+profilee.py:35(factorial) <- profilee.py:25(testfunc)(1) 999.769
+ profilee.py:35(factorial)(20) 169.917
+ profilee.py:84(helper2_indirect)(2) 139.946
+profilee.py:48(mul) <- profilee.py:35(factorial)(20) 169.917
+profilee.py:55(helper) <- profilee.py:25(testfunc)(2) 999.769
+profilee.py:73(helper1) <- profilee.py:55(helper)(4) 599.830
+profilee.py:84(helper2_indirect) <- profilee.py:55(helper)(2) 599.830
+profilee.py:88(helper2) <- profilee.py:55(helper)(6) 599.830
+ profilee.py:84(helper2_indirect)(2) 139.946
+profilee.py:98(subhelper) <- profilee.py:88(helper2)(8) 399.912
+
+
+"""
+ProfileTest.expected_output['print_callees'] = """\
+ Ordered by: standard name
+
+Function called...
+:0(append) ->
+:0(exc_info) ->
+:0(exec) -> <string>:1(<module>)(1) 999.767
+ io.py:1213(flush)(2) -0.010
+:0(hasattr) -> profilee.py:110(__getattr__)(12) 27.972
+:0(setprofile) ->
+<string>:1(<module>) -> profilee.py:25(testfunc)(1) 999.769
+io.py:1213(flush) -> io.py:874(flush)(2) -0.006
+io.py:656(closed) ->
+io.py:874(flush) -> io.py:656(closed)(2) -0.002
+profile:0(profiler) -> profile:0(testfunc())(1) 999.751
+profile:0(testfunc()) -> :0(exec)(1) 999.753
+ :0(setprofile)(1) 0.000
+profilee.py:110(__getattr__) ->
+profilee.py:25(testfunc) -> profilee.py:35(factorial)(1) 169.917
+ profilee.py:55(helper)(2) 599.830
+profilee.py:35(factorial) -> profilee.py:35(factorial)(20) 169.917
+ profilee.py:48(mul)(20) 19.980
+profilee.py:48(mul) ->
+profilee.py:55(helper) -> profilee.py:73(helper1)(4) 119.964
+ profilee.py:84(helper2_indirect)(2) 139.946
+ profilee.py:88(helper2)(6) 399.912
+profilee.py:73(helper1) -> :0(append)(4) -0.004
+ :0(exc_info)(4) -0.004
+ :0(hasattr)(4) 11.964
+profilee.py:84(helper2_indirect) -> profilee.py:35(factorial)(2) 169.917
+ profilee.py:88(helper2)(2) 399.912
+profilee.py:88(helper2) -> :0(hasattr)(8) 11.964
+ profilee.py:98(subhelper)(8) 79.960
+profilee.py:98(subhelper) -> profilee.py:110(__getattr__)(16) 27.972
+
+
+"""
if __name__ == "__main__":
- test_main()
+ main()
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 11251b7..d8d74d0 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -339,11 +339,14 @@ class SysModuleTest(unittest.TestCase):
# freed blocks shouldn't change
self.assertEqual(r[0][2], 0)
# fill freelists
- floats = [float(i) for i in range(12000)]
+ ints = list(range(10000))
+ floats = [float(i) for i in ints]
+ del ints
del floats
- # should free more than 200 blocks
+ # should free more than 100 blocks
r = sys._compact_freelists()
- self.assert_(r[0][2] > 200, r[0][2])
+ self.assert_(r[0][1] > 100, r[0][1])
+ self.assert_(r[0][2] > 100, r[0][2])
def test_main():
test.test_support.run_unittest(SysModuleTest)
diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py
index a0f76c6..635e1bc 100644
--- a/Lib/test/test_trace.py
+++ b/Lib/test/test_trace.py
@@ -252,14 +252,16 @@ class TraceTestCase(unittest.TestCase):
"\n".join(difflib.ndiff([str(x) for x in expected_events],
[str(x) for x in events])))
-
- def run_test(self, func):
+ def run_and_compare(self, func, events):
tracer = Tracer()
sys.settrace(tracer.trace)
func()
sys.settrace(None)
self.compare_events(func.__code__.co_firstlineno,
- tracer.events, func.events)
+ tracer.events, events)
+
+ def run_test(self, func):
+ self.run_and_compare(func, func.events)
def run_test2(self, func):
tracer = Tracer()
@@ -321,6 +323,59 @@ class TraceTestCase(unittest.TestCase):
self.compare_events(generator_example.__code__.co_firstlineno,
tracer.events, generator_example.events)
+ def test_14_onliner_if(self):
+ def onliners():
+ if True: False
+ else: True
+ return 0
+ self.run_and_compare(
+ onliners,
+ [(0, 'call'),
+ (1, 'line'),
+ (3, 'line'),
+ (3, 'return')])
+
+ def test_15_loops(self):
+ # issue1750076: "while" expression is skipped by debugger
+ def for_example():
+ for x in range(2):
+ pass
+ self.run_and_compare(
+ for_example,
+ [(0, 'call'),
+ (1, 'line'),
+ (2, 'line'),
+ (1, 'line'),
+ (2, 'line'),
+ (1, 'line'),
+ (1, 'return')])
+
+ def while_example():
+ # While expression should be traced on every loop
+ x = 2
+ while x > 0:
+ x -= 1
+ self.run_and_compare(
+ while_example,
+ [(0, 'call'),
+ (2, 'line'),
+ (3, 'line'),
+ (4, 'line'),
+ (3, 'line'),
+ (4, 'line'),
+ (3, 'line'),
+ (3, 'return')])
+
+ def test_16_blank_lines(self):
+ namespace = {}
+ exec("def f():\n" + "\n" * 256 + " pass", namespace)
+ self.run_and_compare(
+ namespace["f"],
+ [(0, 'call'),
+ (257, 'line'),
+ (257, 'return')])
+
+
class RaisingTraceFuncTestCase(unittest.TestCase):
def trace(self, frame, event, arg):
"""A trace function that raises an exception in response to a
diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py
index 271f0a8..c37323a 100644
--- a/Lib/test/test_wave.py
+++ b/Lib/test/test_wave.py
@@ -1,32 +1,45 @@
-from test.test_support import TestFailed, TESTFN
+from test.test_support import TESTFN, run_unittest
import os
import wave
-
-def check(t, msg=None):
- if not t:
- raise TestFailed(msg)
+import unittest
nchannels = 2
sampwidth = 2
framerate = 8000
nframes = 100
-f = wave.open(TESTFN, 'wb')
-f.setnchannels(nchannels)
-f.setsampwidth(sampwidth)
-f.setframerate(framerate)
-f.setnframes(nframes)
-output = b'\0' * nframes * nchannels * sampwidth
-f.writeframes(output)
-f.close()
-
-f = wave.open(TESTFN, 'rb')
-check(nchannels == f.getnchannels(), "nchannels")
-check(sampwidth == f.getsampwidth(), "sampwidth")
-check(framerate == f.getframerate(), "framerate")
-check(nframes == f.getnframes(), "nframes")
-input = f.readframes(nframes)
-check(input == output, "data")
-f.close()
-
-os.remove(TESTFN)
+class TestWave(unittest.TestCase):
+
+ def setUp(self):
+ self.f = None
+
+ def tearDown(self):
+ if self.f is not None:
+ self.f.close()
+ try:
+ os.remove(TESTFN)
+ except OSError:
+ pass
+
+ def test_it(self):
+ self.f = wave.open(TESTFN, 'wb')
+ self.f.setnchannels(nchannels)
+ self.f.setsampwidth(sampwidth)
+ self.f.setframerate(framerate)
+ self.f.setnframes(nframes)
+ output = b'\0' * nframes * nchannels * sampwidth
+ self.f.writeframes(output)
+ self.f.close()
+
+ self.f = wave.open(TESTFN, 'rb')
+ self.assertEqual(nchannels, self.f.getnchannels())
+ self.assertEqual(sampwidth, self.f.getsampwidth())
+ self.assertEqual(framerate, self.f.getframerate())
+ self.assertEqual(nframes, self.f.getnframes())
+ self.assertEqual(self.f.readframes(nframes), output)
+
+def test_main():
+ run_unittest(TestWave)
+
+if __name__ == '__main__':
+ test_main()
diff --git a/Misc/python-mode.el b/Misc/python-mode.el
index 5d9af67..1ad818f 100644
--- a/Misc/python-mode.el
+++ b/Misc/python-mode.el
@@ -2,7 +2,8 @@
;; Copyright (C) 1992,1993,1994 Tim Peters
-;; Author: 1995-2002 Barry A. Warsaw
+;; Author: 2003-2007 http://sf.net/projects/python-mode
+;; 1995-2002 Barry A. Warsaw
;; 1992-1994 Tim Peters
;; Maintainer: python-mode@python.org
;; Created: Feb 1992
@@ -19,19 +20,38 @@
;;; Commentary:
-;; This is a major mode for editing Python programs. It was developed
-;; by Tim Peters after an original idea by Michael A. Guravage. Tim
-;; subsequently left the net; in 1995, Barry Warsaw inherited the mode
-;; and is the current maintainer. Tim's now back but disavows all
-;; responsibility for the mode. Smart Tim :-)
+;; This is a major mode for editing Python programs. It was developed by Tim
+;; Peters after an original idea by Michael A. Guravage. Tim subsequently
+;; left the net and in 1995, Barry Warsaw inherited the mode. Tim's now back
+;; but disavows all responsibility for the mode. In fact, we suspect he
+;; doesn't even use Emacs any more. In 2003, python-mode.el was moved to its
+;; own SourceForge project apart from the Python project, and now is
+;; maintained by the volunteers at the python-mode@python.org mailing list.
-;; pdbtrack support contributed by Ken Manheimer, April 2001.
+;; pdbtrack support contributed by Ken Manheimer, April 2001. Skip Montanaro
+;; has also contributed significantly to python-mode's development.
;; Please use the SourceForge Python project to submit bugs or
;; patches:
;;
;; http://sourceforge.net/projects/python
+;; INSTALLATION:
+
+;; To install, just drop this file into a directory on your load-path and
+;; byte-compile it. To set up Emacs to automatically edit files ending in
+;; ".py" using python-mode add the following to your ~/.emacs file (GNU
+;; Emacs) or ~/.xemacs/init.el file (XEmacs):
+;; (setq auto-mode-alist (cons '("\\.py$" . python-mode) auto-mode-alist))
+;; (setq interpreter-mode-alist (cons '("python" . python-mode)
+;; interpreter-mode-alist))
+;; (autoload 'python-mode "python-mode" "Python editing mode." t)
+;;
+;; In XEmacs syntax highlighting should be enabled automatically. In GNU
+;; Emacs you may have to add these lines to your ~/.emacs file:
+;; (global-font-lock-mode t)
+;; (setq font-lock-maximum-decoration t)
+
;; FOR MORE INFORMATION:
;; There is some information on python-mode.el at
@@ -60,6 +80,7 @@
(require 'custom)
(require 'cl)
(require 'compile)
+(require 'ansi-color)
;; user definable variables
@@ -70,34 +91,41 @@
:group 'languages
:prefix "py-")
+(defcustom py-tab-always-indent t
+ "*Non-nil means TAB in Python mode should always reindent the current line,
+regardless of where in the line point is when the TAB command is used."
+ :type 'boolean
+ :group 'python)
+
(defcustom py-python-command "python"
"*Shell command used to start Python interpreter."
:type 'string
:group 'python)
-(defcustom py-jpython-command "jpython"
- "*Shell command used to start the JPython interpreter."
+(make-obsolete-variable 'py-jpython-command 'py-jython-command)
+(defcustom py-jython-command "jython"
+ "*Shell command used to start the Jython interpreter."
:type 'string
:group 'python
- :tag "JPython Command")
+ :tag "Jython Command")
(defcustom py-default-interpreter 'cpython
"*Which Python interpreter is used by default.
-The value for this variable can be either `cpython' or `jpython'.
+The value for this variable can be either `cpython' or `jython'.
When the value is `cpython', the variables `py-python-command' and
`py-python-command-args' are consulted to determine the interpreter
and arguments to use.
-When the value is `jpython', the variables `py-jpython-command' and
-`py-jpython-command-args' are consulted to determine the interpreter
+When the value is `jython', the variables `py-jython-command' and
+`py-jython-command-args' are consulted to determine the interpreter
and arguments to use.
Note that this variable is consulted only the first time that a Python
mode buffer is visited during an Emacs session. After that, use
\\[py-toggle-shells] to change the interpreter shell."
:type '(choice (const :tag "Python (a.k.a. CPython)" cpython)
- (const :tag "JPython" jpython))
+ (const :tag "Jython" jython))
:group 'python)
(defcustom py-python-command-args '("-i")
@@ -105,11 +133,12 @@ mode buffer is visited during an Emacs session. After that, use
:type '(repeat string)
:group 'python)
-(defcustom py-jpython-command-args '("-i")
- "*List of string arguments to be used when starting a JPython shell."
+(make-obsolete-variable 'py-jpython-command-args 'py-jython-command-args)
+(defcustom py-jython-command-args '("-i")
+ "*List of string arguments to be used when starting a Jython shell."
:type '(repeat string)
:group 'python
- :tag "JPython Command Args")
+ :tag "Jython Command Args")
(defcustom py-indent-offset 4
"*Amount of offset per level of indentation.
@@ -248,7 +277,7 @@ Otherwise, all modified buffers are saved without asking."
:type 'function
:group 'python)
-(defcustom py-imenu-show-method-args-p nil
+(defcustom py-imenu-show-method-args-p nil
"*Controls echoing of arguments of functions & methods in the Imenu buffer.
When non-nil, arguments are printed."
:type 'boolean
@@ -275,19 +304,20 @@ as gud-mode does for debugging C programs with gdb."
20000
"Maximum number of characters to search for a Java-ish import statement.
When `python-mode' tries to calculate the shell to use (either a
-CPython or a JPython shell), it looks at the so-called `shebang' line
+CPython or a Jython shell), it looks at the so-called `shebang' line
-- i.e. #! line. If that's not available, it looks at some of the
file heading imports to see if they look Java-like."
:type 'integer
:group 'python
)
-(defcustom py-jpython-packages
+(make-obsolete-variable 'py-jpython-packages 'py-jython-packages)
+(defcustom py-jython-packages
'("java" "javax" "org" "com")
- "Imported packages that imply `jpython-mode'."
+ "Imported packages that imply `jython-mode'."
:type '(repeat string)
:group 'python)
-
+
;; Not customizable
(defvar py-master-file nil
"If non-nil, execute the named file instead of the buffer's file.
@@ -317,16 +347,39 @@ buffer is prepended to come up with a file name.")
:tag "Pychecker Command Args")
(defvar py-shell-alist
- '(("jpython" . 'jpython)
- ("jython" . 'jpython)
+ '(("jython" . 'jython)
("python" . 'cpython))
"*Alist of interpreters and python shells. Used by `py-choose-shell'
to select the appropriate python interpreter mode for a file.")
+(defcustom py-shell-input-prompt-1-regexp "^>>> "
+ "*A regular expression to match the input prompt of the shell."
+ :type 'string
+ :group 'python)
+
+(defcustom py-shell-input-prompt-2-regexp "^[.][.][.] "
+ "*A regular expression to match the input prompt of the shell after the
+ first line of input."
+ :type 'string
+ :group 'python)
+
+(defcustom py-shell-switch-buffers-on-execute t
+ "*Controls switching to the Python buffer where commands are
+ executed. When non-nil the buffer switches to the Python buffer, if
+ not no switching occurs."
+ :type 'boolean
+ :group 'python)
+
;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;; NO USER DEFINABLE VARIABLES BEYOND THIS POINT
+(defvar py-line-number-offset 0
+ "When an exception occurs as a result of py-execute-region, a
+subsequent py-up-exception needs the line number where the region
+started, in order to jump to the correct file line. This variable is
+set in py-execute-region and used in py-jump-to-exception.")
+
(defconst py-emacs-features
(let (features)
features)
@@ -339,9 +392,31 @@ support for features needed by `python-mode'.")
"Face for pseudo keywords in Python mode, like self, True, False, Ellipsis.")
(make-face 'py-pseudo-keyword-face)
+;; PEP 318 decorators
+(defvar py-decorators-face 'py-decorators-face
+ "Face method decorators.")
+(make-face 'py-decorators-face)
+
+;; Face for builtins
+(defvar py-builtins-face 'py-builtins-face
+ "Face for builtins like TypeError, object, open, and exec.")
+(make-face 'py-builtins-face)
+
+;; XXX, TODO, and FIXME comments and such
+(defvar py-XXX-tag-face 'py-XXX-tag-face
+ "Face for XXX, TODO, and FIXME tags")
+(make-face 'py-XXX-tag-face)
+
(defun py-font-lock-mode-hook ()
(or (face-differs-from-default-p 'py-pseudo-keyword-face)
- (copy-face 'font-lock-keyword-face 'py-pseudo-keyword-face)))
+ (copy-face 'font-lock-keyword-face 'py-pseudo-keyword-face))
+ (or (face-differs-from-default-p 'py-builtins-face)
+ (copy-face 'font-lock-keyword-face 'py-builtins-face))
+ (or (face-differs-from-default-p 'py-decorators-face)
+ (copy-face 'py-pseudo-keyword-face 'py-decorators-face))
+ (or (face-differs-from-default-p 'py-XXX-tag-face)
+ (copy-face 'font-lock-comment-face 'py-XXX-tag-face))
+ )
(add-hook 'font-lock-mode-hook 'py-font-lock-mode-hook)
(defvar python-font-lock-keywords
@@ -352,7 +427,7 @@ support for features needed by `python-mode'.")
"from" "global" "if" "import"
"in" "is" "lambda" "not"
"or" "pass" "print" "raise"
- "return" "while" "yield"
+ "return" "while" "with" "yield"
)
"\\|"))
(kw2 (mapconcat 'identity
@@ -391,26 +466,52 @@ support for features needed by `python-mode'.")
"super" "tuple" "type" "unichr" "unicode" "vars"
"zip")
"\\|"))
+ (kw4 (mapconcat 'identity
+ ;; Exceptions and warnings
+ '("ArithmeticError" "AssertionError"
+ "AttributeError" "DeprecationWarning" "EOFError"
+ "EnvironmentError" "Exception"
+ "FloatingPointError" "FutureWarning" "IOError"
+ "ImportError" "IndentationError" "IndexError"
+ "KeyError" "KeyboardInterrupt" "LookupError"
+ "MemoryError" "NameError" "NotImplemented"
+ "NotImplementedError" "OSError" "OverflowError"
+ "OverflowWarning" "PendingDeprecationWarning"
+ "ReferenceError" "RuntimeError" "RuntimeWarning"
+ "StandardError" "StopIteration" "SyntaxError"
+ "SyntaxWarning" "SystemError" "SystemExit"
+ "TabError" "TypeError" "UnboundLocalError"
+ "UnicodeDecodeError" "UnicodeEncodeError"
+ "UnicodeError" "UnicodeTranslateError"
+ "UserWarning" "ValueError" "Warning"
+ "ZeroDivisionError")
+ "\\|"))
)
(list
+ '("^[ \t]*\\(@.+\\)" 1 'py-decorators-face)
;; keywords
- (cons (concat "\\b\\(" kw1 "\\)\\b[ \n\t(]") 1)
+ (cons (concat "\\<\\(" kw1 "\\)\\>[ \n\t(]") 1)
;; builtins when they don't appear as object attributes
- (cons (concat "\\(\\b\\|[.]\\)\\(" kw3 "\\)\\b[ \n\t(]") 2)
+ (list (concat "\\([^. \t]\\|^\\)[ \t]*\\<\\(" kw3 "\\)\\>[ \n\t(]") 2
+ 'py-builtins-face)
;; block introducing keywords with immediately following colons.
;; Yes "except" is in both lists.
- (cons (concat "\\b\\(" kw2 "\\)[ \n\t(]") 1)
- ;; `as' but only in "import foo as bar"
- '("[ \t]*\\(\\bfrom\\b.*\\)?\\bimport\\b.*\\b\\(as\\)\\b" . 2)
+ (cons (concat "\\<\\(" kw2 "\\)[ \n\t(]") 1)
+ ;; Exceptions
+ (list (concat "\\<\\(" kw4 "\\)[ \n\t:,(]") 1 'py-builtins-face)
+ ;; `as' but only in "import foo as bar" or "with foo as bar"
+ '("[ \t]*\\(\\<from\\>.*\\)?\\<import\\>.*\\<\\(as\\)\\>" . 2)
+ '("[ \t]*\\<with\\>.*\\<\\(as\\)\\>" . 1)
;; classes
- '("\\bclass[ \t]+\\([a-zA-Z_]+[a-zA-Z0-9_]*\\)"
- 1 font-lock-type-face)
+ '("\\<class[ \t]+\\([a-zA-Z_]+[a-zA-Z0-9_]*\\)" 1 font-lock-type-face)
;; functions
- '("\\bdef[ \t]+\\([a-zA-Z_]+[a-zA-Z0-9_]*\\)"
+ '("\\<def[ \t]+\\([a-zA-Z_]+[a-zA-Z0-9_]*\\)"
1 font-lock-function-name-face)
;; pseudo-keywords
- '("\\b\\(self\\|None\\|True\\|False\\|Ellipsis\\)\\b"
+ '("\\<\\(self\\|None\\|True\\|False\\|Ellipsis\\)\\>"
1 py-pseudo-keyword-face)
+ ;; XXX, TODO, and FIXME tags
+ '("XXX\\|TODO\\|FIXME" 0 py-XXX-tag-face t)
))
"Additional expressions to highlight in Python mode.")
(put 'python-mode 'font-lock-defaults '(python-font-lock-keywords))
@@ -421,13 +522,7 @@ support for features needed by `python-mode'.")
Currently-active file is at the head of the list.")
(defvar py-pdbtrack-is-tracking-p nil)
-(defvar py-pdbtrack-last-grubbed-buffer nil
- "Record of the last buffer used when the source path was invalid.
-This buffer is consulted before the buffer-list history for satisfying
-`py-pdbtrack-grub-for-buffer', since it's the most often the likely
-prospect as debugging continues.")
-(make-variable-buffer-local 'py-pdbtrack-last-grubbed-buffer)
(defvar py-pychecker-history nil)
@@ -461,7 +556,7 @@ prospect as debugging continues.")
"\\(" "[^#'\"\n\\]" "\\|" py-stringlit-re "\\)*"
"\\\\$")
"Regular expression matching Python backslash continuation lines.")
-
+
(defconst py-blank-or-comment-re "[ \t]*\\($\\|#\\)"
"Regular expression matching a blank or comment line.")
@@ -474,7 +569,7 @@ prospect as debugging continues.")
"\\|")
"\\)")
"Regular expression matching statements to be dedented one level.")
-
+
(defconst py-block-closing-keywords-re
"\\(return\\|raise\\|break\\|continue\\|pass\\)"
"Regular expression matching keywords which typically close a block.")
@@ -495,30 +590,17 @@ prospect as debugging continues.")
"\\)")
"Regular expression matching lines not to dedent after.")
-(defconst py-defun-start-re
- "^\\([ \t]*\\)def[ \t]+\\([a-zA-Z_0-9]+\\)\\|\\(^[a-zA-Z_0-9]+\\)[ \t]*="
- ;; If you change this, you probably have to change py-current-defun
- ;; as well. This is only used by py-current-defun to find the name
- ;; for add-log.el.
- "Regular expression matching a function, method, or variable assignment.")
-
-(defconst py-class-start-re "^class[ \t]*\\([a-zA-Z_0-9]+\\)"
- ;; If you change this, you probably have to change py-current-defun
- ;; as well. This is only used by py-current-defun to find the name
- ;; for add-log.el.
- "Regular expression for finding a class name.")
-
-(defconst py-traceback-line-re
+(defvar py-traceback-line-re
"[ \t]+File \"\\([^\"]+\\)\", line \\([0-9]+\\)"
"Regular expression that describes tracebacks.")
-;; pdbtrack contants
+;; pdbtrack constants
(defconst py-pdbtrack-stack-entry-regexp
; "^> \\([^(]+\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_]+\\)()"
"^> \\(.*\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_]+\\)()"
"Regular expression pdbtrack uses to find a stack trace entry.")
-(defconst py-pdbtrack-input-prompt "\n[(<]*pdb[>)]+ "
+(defconst py-pdbtrack-input-prompt "\n[(<]*[Pp]db[>)]+ "
"Regular expression pdbtrack uses to recognize a pdb prompt.")
(defconst py-pdbtrack-track-range 10000
@@ -536,8 +618,9 @@ prospect as debugging continues.")
(defvar python-mode-hook nil
"*Hook called by `python-mode'.")
-(defvar jpython-mode-hook nil
- "*Hook called by `jpython-mode'. `jpython-mode' also calls
+(make-obsolete-variable 'jpython-mode-hook 'jython-mode-hook)
+(defvar jython-mode-hook nil
+ "*Hook called by `jython-mode'. `jython-mode' also calls
`python-mode-hook'.")
(defvar py-shell-hook nil
@@ -560,8 +643,6 @@ prospect as debugging continues.")
(define-key py-mode-map "\C-c\C-r" 'py-shift-region-right)
(define-key py-mode-map "\C-c<" 'py-shift-region-left)
(define-key py-mode-map "\C-c>" 'py-shift-region-right)
- ;; paragraph and string filling
- (define-key py-mode-map "\eq" 'py-fill-paragraph)
;; subprocess commands
(define-key py-mode-map "\C-c\C-c" 'py-execute-buffer)
(define-key py-mode-map "\C-c\C-m" 'py-execute-import-or-reload)
@@ -624,7 +705,7 @@ prospect as debugging continues.")
;; expect RET to do a `py-newline-and-indent' and any Emacsers who
;; dislike this are probably knowledgeable enough to do a rebind.
;; However, we do *not* change C-j since many Emacsers have already
- ;; swapped RET and C-j and they don't want C-j bound to `newline' to
+ ;; swapped RET and C-j and they don't want C-j bound to `newline' to
;; change.
(define-key py-mode-map "\C-m" 'py-newline-and-indent)
)
@@ -740,8 +821,8 @@ This function does not modify point or mark."
(cond
((eq position 'bol) (beginning-of-line))
((eq position 'eol) (end-of-line))
- ((eq position 'bod) (py-beginning-of-def-or-class))
- ((eq position 'eod) (py-end-of-def-or-class))
+ ((eq position 'bod) (py-beginning-of-def-or-class 'either))
+ ((eq position 'eod) (py-end-of-def-or-class 'either))
;; Kind of funny, I know, but useful for py-up-exception.
((eq position 'bob) (beginning-of-buffer))
((eq position 'eob) (end-of-buffer))
@@ -849,7 +930,7 @@ package. Note that the latest X/Emacs releases contain this package.")
(defvar py-imenu-method-regexp
(concat ; <<methods and functions>>
- "\\(" ;
+ "\\(" ;
"^[ \t]*" ; new line and maybe whitespace
"\\(def[ \t]+" ; function definitions start with def
"\\([a-zA-Z0-9_]+\\)" ; name is here
@@ -885,7 +966,7 @@ information.")
;; it.
(defvar py-imenu-generic-expression
(cons
- (concat
+ (concat
py-imenu-class-regexp
"\\|" ; or...
py-imenu-method-regexp
@@ -954,7 +1035,7 @@ of the first definition found."
looking-p
def-name prev-name
cur-indent def-pos
- (class-paren (first py-imenu-generic-parens))
+ (class-paren (first py-imenu-generic-parens))
(def-paren (second py-imenu-generic-parens)))
(setq looking-p
(re-search-forward py-imenu-generic-regexp (point-max) t))
@@ -1009,7 +1090,7 @@ of the first definition found."
(cons save-elmt sub-method-alist))
index-alist))))
;; found less indented expression, we're done.
- (t
+ (t
(setq looking-p nil)
(re-search-backward py-imenu-generic-regexp (point-min) t)))
;; end-cond
@@ -1023,7 +1104,7 @@ of the first definition found."
(defun py-choose-shell-by-shebang ()
- "Choose CPython or JPython mode by looking at #! on the first line.
+ "Choose CPython or Jython mode by looking at #! on the first line.
Returns the appropriate mode function.
Used by `py-choose-shell', and similar to but distinct from
`set-auto-mode', though it uses `auto-mode-interpreter-regexp' (if available)."
@@ -1047,10 +1128,10 @@ Used by `py-choose-shell', and similar to but distinct from
(defun py-choose-shell-by-import ()
- "Choose CPython or JPython mode based imports.
-If a file imports any packages in `py-jpython-packages', within
+ "Choose CPython or Jython mode based imports.
+If a file imports any packages in `py-jython-packages', within
`py-import-check-point-max' characters from the start of the file,
-return `jpython', otherwise return nil."
+return `jython', otherwise return nil."
(let (mode)
(save-excursion
(goto-char (point-min))
@@ -1058,14 +1139,14 @@ return `jpython', otherwise return nil."
(search-forward-regexp
"^\\(\\(from\\)\\|\\(import\\)\\) \\([^ \t\n.]+\\)"
py-import-check-point-max t))
- (setq mode (and (member (match-string 4) py-jpython-packages)
- 'jpython
+ (setq mode (and (member (match-string 4) py-jython-packages)
+ 'jython
))))
mode))
(defun py-choose-shell ()
- "Choose CPython or JPython mode. Returns the appropriate mode function.
+ "Choose CPython or Jython mode. Returns the appropriate mode function.
This does the following:
- look for an interpreter with `py-choose-shell-by-shebang'
- examine imports using `py-choose-shell-by-import'
@@ -1114,6 +1195,7 @@ py-beep-if-tab-change\t\tring the bell if `tab-width' is changed"
(make-local-variable 'indent-region-function)
(make-local-variable 'indent-line-function)
(make-local-variable 'add-log-current-defun-function)
+ (make-local-variable 'fill-paragraph-function)
;;
(set-syntax-table py-mode-syntax-table)
(setq major-mode 'python-mode
@@ -1132,6 +1214,8 @@ py-beep-if-tab-change\t\tring the bell if `tab-width' is changed"
indent-line-function 'py-indent-line
;; tell add-log.el how to find the current function/method/variable
add-log-current-defun-function 'py-current-defun
+
+ fill-paragraph-function 'py-fill-paragraph
)
(use-local-map py-mode-map)
;; add the menu
@@ -1171,17 +1255,18 @@ py-beep-if-tab-change\t\tring the bell if `tab-width' is changed"
(py-toggle-shells (py-choose-shell))))
-(defun jpython-mode ()
- "Major mode for editing JPython/Jython files.
+(make-obsolete 'jpython-mode 'jython-mode)
+(defun jython-mode ()
+ "Major mode for editing Jython/Jython files.
This is a simple wrapper around `python-mode'.
-It runs `jpython-mode-hook' then calls `python-mode.'
+It runs `jython-mode-hook' then calls `python-mode.'
It is added to `interpreter-mode-alist' and `py-choose-shell'.
"
(interactive)
(python-mode)
- (py-toggle-shells 'jpython)
- (when jpython-mode-hook
- (run-hooks 'jpython-mode-hook)))
+ (py-toggle-shells 'jython)
+ (when jython-mode-hook
+ (run-hooks 'jython-mode-hook)))
;; It's handy to add recognition of Python files to the
@@ -1189,16 +1274,16 @@ It is added to `interpreter-mode-alist' and `py-choose-shell'.
;; can specify different `derived-modes' based on the #! line, but
;; with the latter, we can't. So we just won't add them if they're
;; already added.
-(let ((modes '(("jpython" . jpython-mode)
- ("jython" . jpython-mode)
+;;;###autoload
+(let ((modes '(("jython" . jython-mode)
("python" . python-mode))))
(while modes
(when (not (assoc (car modes) interpreter-mode-alist))
(push (car modes) interpreter-mode-alist))
(setq modes (cdr modes))))
-
+;;;###autoload
(when (not (or (rassq 'python-mode auto-mode-alist)
- (rassq 'jpython-mode auto-mode-alist)))
+ (rassq 'jython-mode auto-mode-alist)))
(push '("\\.py$" . python-mode) auto-mode-alist))
@@ -1283,12 +1368,13 @@ comint believe the user typed this string so that
(defun py-comint-output-filter-function (string)
"Watch output for Python prompt and exec next file waiting in queue.
This function is appropriate for `comint-output-filter-functions'."
- ;; TBD: this should probably use split-string
- (when (and (or (string-equal string ">>> ")
- (and (>= (length string) 5)
- (string-equal (substring string -5) "\n>>> ")))
- py-file-queue)
- (pop-to-buffer (current-buffer))
+ ;;remove ansi terminal escape sequences from string, not sure why they are
+ ;;still around...
+ (setq string (ansi-color-filter-apply string))
+ (when (and (string-match py-shell-input-prompt-1-regexp string)
+ py-file-queue)
+ (if py-shell-switch-buffers-on-execute
+ (pop-to-buffer (current-buffer)))
(py-safe (delete-file (car py-file-queue)))
(setq py-file-queue (cdr py-file-queue))
(if py-file-queue
@@ -1344,7 +1430,7 @@ script, and set to python-mode, and pdbtrack will find it.)"
(- procmark
py-pdbtrack-track-range))
procmark))
- target target_fname target_lineno)
+ target target_fname target_lineno target_buffer)
(if (not (string-match (concat py-pdbtrack-input-prompt "$") block))
(py-pdbtrack-overlay-arrow nil)
@@ -1372,8 +1458,7 @@ script, and set to python-mode, and pdbtrack will find it.)"
We look first to visit the file indicated in the trace.
Failing that, we look for the most recently visited python-mode buffer
-with the same name or having
-having the named function.
+with the same name or having the named function.
If we're unable find the source code we return a string describing the
problem as best as we can determine."
@@ -1417,11 +1502,10 @@ problem as best as we can determine."
(defun py-pdbtrack-grub-for-buffer (funcname lineno)
"Find most recent buffer itself named or having function funcname.
-We first check the last buffer this function found, if any, then walk
-throught the buffer-list history for python-mode buffers that are
+We walk the buffer-list history for python-mode buffers that are
named for funcname or define a function funcname."
(let ((buffers (buffer-list))
- curbuf
+ buf
got)
(while (and buffers (not got))
(setq buf (car buffers)
@@ -1436,7 +1520,7 @@ named for funcname or define a function funcname."
(buffer-substring (point-min)
(point-max))))))
(setq got buf)))
- (setq py-pdbtrack-last-grubbed-buffer got)))
+ got))
(defun py-postprocess-output-buffer (buf)
"Highlight exceptions found in BUF.
@@ -1466,7 +1550,7 @@ If an exception occurred return t, otherwise return nil. BUF must exist."
(defconst py-output-buffer "*Python Output*")
(make-variable-buffer-local 'py-output-buffer)
-;; for toggling between CPython and JPython
+;; for toggling between CPython and Jython
(defvar py-which-shell nil)
(defvar py-which-args py-python-command-args)
(defvar py-which-bufname "Python")
@@ -1475,14 +1559,14 @@ If an exception occurred return t, otherwise return nil. BUF must exist."
(make-variable-buffer-local 'py-which-bufname)
(defun py-toggle-shells (arg)
- "Toggles between the CPython and JPython shells.
+ "Toggles between the CPython and Jython shells.
With positive argument ARG (interactively \\[universal-argument]),
-uses the CPython shell, with negative ARG uses the JPython shell, and
+uses the CPython shell, with negative ARG uses the Jython shell, and
with a zero argument, toggles the shell.
Programmatically, ARG can also be one of the symbols `cpython' or
-`jpython', equivalent to positive arg and negative arg respectively."
+`jython', equivalent to positive arg and negative arg respectively."
(interactive "P")
;; default is to toggle
(if (null arg)
@@ -1495,7 +1579,7 @@ Programmatically, ARG can also be one of the symbols `cpython' or
(setq arg -1)
(setq arg 1)))
((equal arg 'cpython) (setq arg 1))
- ((equal arg 'jpython) (setq arg -1)))
+ ((equal arg 'jython) (setq arg -1)))
(let (msg)
(cond
((< 0 arg)
@@ -1503,14 +1587,16 @@ Programmatically, ARG can also be one of the symbols `cpython' or
(setq py-which-shell py-python-command
py-which-args py-python-command-args
py-which-bufname "Python"
- msg "CPython"
- mode-name "Python"))
+ msg "CPython")
+ (if (string-equal py-which-bufname "Jython")
+ (setq mode-name "Python")))
((> 0 arg)
- (setq py-which-shell py-jpython-command
- py-which-args py-jpython-command-args
- py-which-bufname "JPython"
- msg "JPython"
- mode-name "JPython"))
+ (setq py-which-shell py-jython-command
+ py-which-args py-jython-command-args
+ py-which-bufname "Jython"
+ msg "Jython")
+ (if (string-equal py-which-bufname "Python")
+ (setq mode-name "Jython")))
)
(message "Using the %s shell" msg)
(setq py-output-buffer (format "*%s Output*" py-which-bufname))))
@@ -1532,9 +1618,9 @@ prompt). This argument is ignored when this function is called
programmatically, or when running in Emacs 19.34 or older.
Note: You can toggle between using the CPython interpreter and the
-JPython interpreter by hitting \\[py-toggle-shells]. This toggles
+Jython interpreter by hitting \\[py-toggle-shells]. This toggles
buffer local variables which control whether all your subshell
-interactions happen to the `*JPython*' or `*Python*' buffers (the
+interactions happen to the `*Jython*' or `*Python*' buffers (the
latter is the name used for the CPython buffer).
Warning: Don't use an interactive Python if you change sys.ps1 or
@@ -1568,10 +1654,14 @@ filter."
(concat
(mapconcat 'identity py-which-args " ") " ")
))))
- (switch-to-buffer-other-window
- (apply 'make-comint py-which-bufname py-which-shell nil args))
+ (if (not (equal (buffer-name) "*Python*"))
+ (switch-to-buffer-other-window
+ (apply 'make-comint py-which-bufname py-which-shell nil args))
+ (apply 'make-comint py-which-bufname py-which-shell nil args))
(make-local-variable 'comint-prompt-regexp)
- (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ")
+ (setq comint-prompt-regexp (concat py-shell-input-prompt-1-regexp "\\|"
+ py-shell-input-prompt-2-regexp "\\|"
+ "^([Pp]db) "))
(add-hook 'comint-output-filter-functions
'py-comint-output-filter-function)
;; pdbtrack
@@ -1642,11 +1732,13 @@ is inserted at the end. See also the command `py-clear-queue'."
(setq start (point))
(or (< start end)
(error "Region is empty"))
+ (setq py-line-number-offset (count-lines 1 start))
(let ((needs-if (/= (py-point 'bol) (py-point 'boi))))
(set-buffer buf)
(python-mode)
(when needs-if
- (insert "if 1:\n"))
+ (insert "if 1:\n")
+ (setq py-line-number-offset (- py-line-number-offset 1)))
(insert-buffer-substring cur start end)
;; Set the shell either to the #! line command, or to the
;; py-which-shell buffer local variable.
@@ -1683,8 +1775,9 @@ is inserted at the end. See also the command `py-clear-queue'."
(setq py-exception-buffer (cons file (current-buffer))))
(t
;; TBD: a horrible hack, but why create new Custom variables?
- (let ((cmd (concat shell (if (string-equal py-which-bufname "JPython")
- " -" ""))))
+ (let ((cmd (concat py-which-shell (if (string-equal py-which-bufname
+ "Jython")
+ " -" ""))))
;; otherwise either run it synchronously in a subprocess
(save-excursion
(set-buffer buf)
@@ -1718,12 +1811,14 @@ sent. A trailing newline will be supplied if needed.
See the `\\[py-execute-region]' docs for an account of some
subtleties, including the use of the optional ASYNC argument."
(interactive "P")
- (if py-master-file
- (let* ((filename (expand-file-name py-master-file))
- (buffer (or (get-file-buffer filename)
- (find-file-noselect filename))))
- (set-buffer buffer)))
- (py-execute-region (point-min) (point-max) async))
+ (let ((old-buffer (current-buffer)))
+ (if py-master-file
+ (let* ((filename (expand-file-name py-master-file))
+ (buffer (or (get-file-buffer filename)
+ (find-file-noselect filename))))
+ (set-buffer buffer)))
+ (py-execute-region (point-min) (point-max) async)
+ (pop-to-buffer old-buffer)))
(defun py-execute-import-or-reload (&optional async)
"Import the current buffer's file in a Python interpreter.
@@ -1819,6 +1914,9 @@ subtleties, including the use of the optional ASYNC argument."
(t (find-file (read-file-name "Exception file: "
nil
file t))))))
+ ;; Fiddle about with line number
+ (setq line (+ py-line-number-offset line))
+
(pop-to-buffer buffer)
;; Force Python mode
(if (not (eq major-mode 'python-mode))
@@ -1999,16 +2097,29 @@ This function is normally bound to `indent-line-function' so
(interactive "P")
(let* ((ci (current-indentation))
(move-to-indentation-p (<= (current-column) ci))
- (need (py-compute-indentation (not arg))))
- ;; see if we need to dedent
- (if (py-outdent-p)
- (setq need (- need py-indent-offset)))
- (if (/= ci need)
- (save-excursion
- (beginning-of-line)
- (delete-horizontal-space)
- (indent-to need)))
- (if move-to-indentation-p (back-to-indentation))))
+ (need (py-compute-indentation (not arg)))
+ (cc (current-column)))
+ ;; dedent out a level if previous command was the same unless we're in
+ ;; column 1
+ (if (and (equal last-command this-command)
+ (/= cc 0))
+ (progn
+ (beginning-of-line)
+ (delete-horizontal-space)
+ (indent-to (* (/ (- cc 1) py-indent-offset) py-indent-offset)))
+ (progn
+ ;; see if we need to dedent
+ (if (py-outdent-p)
+ (setq need (- need py-indent-offset)))
+ (if (or py-tab-always-indent
+ move-to-indentation-p)
+ (progn (if (/= ci need)
+ (save-excursion
+ (beginning-of-line)
+ (delete-horizontal-space)
+ (indent-to need)))
+ (if move-to-indentation-p (back-to-indentation)))
+ (insert-tab))))))
(defun py-newline-and-indent ()
"Strives to act like the Emacs `newline-and-indent'.
@@ -2052,39 +2163,23 @@ dedenting."
((py-continuation-line-p)
(let ((startpos (point))
(open-bracket-pos (py-nesting-level))
- endpos searching found state)
+ endpos searching found state cind cline)
(if open-bracket-pos
(progn
- ;; align with first item in list; else a normal
- ;; indent beyond the line with the open bracket
- (goto-char (1+ open-bracket-pos)) ; just beyond bracket
- ;; is the first list item on the same line?
- (skip-chars-forward " \t")
- (if (null (memq (following-char) '(?\n ?# ?\\)))
- ; yes, so line up with it
- (current-column)
- ;; first list item on another line, or doesn't exist yet
- (forward-line 1)
- (while (and (< (point) startpos)
- (looking-at "[ \t]*[#\n\\\\]")) ; skip noise
- (forward-line 1))
- (if (and (< (point) startpos)
- (/= startpos
- (save-excursion
- (goto-char (1+ open-bracket-pos))
- (forward-comment (point-max))
- (point))))
- ;; again mimic the first list item
- (current-indentation)
- ;; else they're about to enter the first item
- (goto-char open-bracket-pos)
- (setq placeholder (point))
- (py-goto-initial-line)
- (py-goto-beginning-of-tqs
- (save-excursion (nth 3 (parse-partial-sexp
- placeholder (point)))))
- (+ (current-indentation) py-indent-offset))))
-
+ (setq endpos (py-point 'bol))
+ (py-goto-initial-line)
+ (setq cind (current-indentation))
+ (setq cline cind)
+ (dolist (bp
+ (nth 9 (save-excursion
+ (parse-partial-sexp (point) endpos)))
+ cind)
+ (if (search-forward "\n" bp t) (setq cline cind))
+ (goto-char (1+ bp))
+ (skip-chars-forward " \t")
+ (setq cind (if (memq (following-char) '(?\n ?# ?\\))
+ (+ cline py-indent-offset)
+ (current-column)))))
;; else on backslash continuation line
(forward-line -1)
(if (py-continuation-line-p) ; on at least 3rd line in block
@@ -2832,7 +2927,7 @@ pleasant."
;; ripped from cc-mode
(defun py-forward-into-nomenclature (&optional arg)
"Move forward to end of a nomenclature section or word.
-With \\[universal-argument] (programmatically, optional argument ARG),
+With \\[universal-argument] (programmatically, optional argument ARG),
do it that many times.
A `nomenclature' is a fancy way of saying AWordWithMixedCaseNotUnderscores."
@@ -2886,6 +2981,11 @@ A `nomenclature' is a fancy way of saying AWordWithMixedCaseNotUnderscores."
;; Pychecker
+
+;; hack for FSF Emacs
+(unless (fboundp 'read-shell-command)
+ (defalias 'read-shell-command 'read-string))
+
(defun py-pychecker-run (command)
"*Run pychecker (default on the file currently visited)."
(interactive
@@ -3410,7 +3510,7 @@ multi-line statement we need to skip over the continuation lines."
(defun py-statement-opens-block-p ()
"Return t iff the current statement opens a block.
-I.e., iff it ends with a colon that is not in a comment. Point should
+I.e., iff it ends with a colon that is not in a comment. Point should
be at the start of a statement."
(save-excursion
(let ((start (point))
@@ -3494,8 +3594,8 @@ does not include blank lines, comments, or continuation lines."
KEY is a regular expression describing a Python keyword. Skip blank
lines and non-indenting comments. If the statement found starts with
KEY, then stop, otherwise go back to first enclosing block starting
-with KEY. If successful, leave point at the start of the KEY line and
-return t. Otherwise, leav point at an undefined place and return nil."
+with KEY. If successful, leave point at the start of the KEY line and
+return t. Otherwise, leave point at an undefined place and return nil."
;; skip blanks and non-indenting #
(py-goto-initial-line)
(while (and
@@ -3503,7 +3603,7 @@ return t. Otherwise, leav point at an undefined place and return nil."
(zerop (forward-line -1))) ; go back
nil)
(py-goto-initial-line)
- (let* ((re (concat "[ \t]*" key "\\b"))
+ (let* ((re (concat "[ \t]*" key "\\>"))
(case-fold-search nil) ; let* so looking-at sees this
(found (looking-at re))
(dead nil))
@@ -3529,7 +3629,7 @@ Prefix with \"...\" if leading whitespace was skipped."
`Keyword' is defined (essentially) as the regular expression
([a-z]+). Returns nil if none was found."
(let ((case-fold-search nil))
- (if (looking-at "[ \t]*\\([a-z]+\\)\\b")
+ (if (looking-at "[ \t]*\\([a-z]+\\)\\>")
(intern (buffer-substring (match-beginning 1) (match-end 1)))
nil)))
@@ -3537,14 +3637,49 @@ Prefix with \"...\" if leading whitespace was skipped."
"Python value for `add-log-current-defun-function'.
This tells add-log.el how to find the current function/method/variable."
(save-excursion
- (if (re-search-backward py-defun-start-re nil t)
- (or (match-string 3)
- (let ((method (match-string 2)))
- (if (and (not (zerop (length (match-string 1))))
- (re-search-backward py-class-start-re nil t))
- (concat (match-string 1) "." method)
- method)))
- nil)))
+
+ ;; Move back to start of the current statement.
+
+ (py-goto-initial-line)
+ (back-to-indentation)
+ (while (and (or (looking-at py-blank-or-comment-re)
+ (py-in-literal))
+ (not (bobp)))
+ (backward-to-indentation 1))
+ (py-goto-initial-line)
+
+ (let ((scopes "")
+ (sep "")
+ dead assignment)
+
+ ;; Check for an assignment. If this assignment exists inside a
+ ;; def, it will be overwritten inside the while loop. If it
+ ;; exists at top lever or inside a class, it will be preserved.
+
+ (when (looking-at "[ \t]*\\([a-zA-Z0-9_]+\\)[ \t]*=")
+ (setq scopes (buffer-substring (match-beginning 1) (match-end 1)))
+ (setq assignment t)
+ (setq sep "."))
+
+ ;; Prepend the name of each outer socpe (def or class).
+
+ (while (not dead)
+ (if (and (py-go-up-tree-to-keyword "\\(class\\|def\\)")
+ (looking-at
+ "[ \t]*\\(class\\|def\\)[ \t]*\\([a-zA-Z0-9_]+\\)[ \t]*"))
+ (let ((name (buffer-substring (match-beginning 2) (match-end 2))))
+ (if (and assignment (looking-at "[ \t]*def"))
+ (setq scopes name)
+ (setq scopes (concat name sep scopes))
+ (setq sep "."))))
+ (setq assignment nil)
+ (condition-case nil ; Terminate nicely at top level.
+ (py-goto-block-up 'no-mark)
+ (error (setq dead t))))
+ (if (string= scopes "")
+ nil
+ scopes))))
+
(defconst py-help-address "python-mode@python.org"
@@ -3586,7 +3721,7 @@ non-nil) just submit an enhancement request."
"Dear Barry,") ;salutation
(if enhancement-p nil
(set-mark (point))
- (insert
+ (insert
"Please replace this text with a sufficiently large code sample\n\
and an exact recipe so that I can reproduce your problem. Failure\n\
to do so may mean a greater delay in fixing your bug.\n\n")
@@ -3606,7 +3741,7 @@ These are Python temporary files awaiting execution."
(add-hook 'comint-output-filter-functions 'py-pdbtrack-track-stack-file)
;; Add a designator to the minor mode strings
-(or (assq 'py-pdbtrack-minor-mode-string minor-mode-alist)
+(or (assq 'py-pdbtrack-is-tracking-p minor-mode-alist)
(push '(py-pdbtrack-is-tracking-p py-pdbtrack-minor-mode-string)
minor-mode-alist))
@@ -3745,20 +3880,35 @@ and initial `#'s.
If point is inside a string, narrow to that string and fill.
"
(interactive "P")
- (let* ((bod (py-point 'bod))
- (pps (parse-partial-sexp bod (point))))
- (cond
- ;; are we inside a comment or on a line with only whitespace before
- ;; the comment start?
- ((or (nth 4 pps)
- (save-excursion (beginning-of-line) (looking-at "[ \t]*#")))
- (py-fill-comment justify))
- ;; are we inside a string?
- ((nth 3 pps)
- (py-fill-string (nth 8 pps)))
- ;; otherwise use the default
- (t
- (fill-paragraph justify)))))
+ ;; fill-paragraph will narrow incorrectly
+ (save-restriction
+ (widen)
+ (let* ((bod (py-point 'bod))
+ (pps (parse-partial-sexp bod (point))))
+ (cond
+ ;; are we inside a comment or on a line with only whitespace before
+ ;; the comment start?
+ ((or (nth 4 pps)
+ (save-excursion (beginning-of-line) (looking-at "[ \t]*#")))
+ (py-fill-comment justify))
+ ;; are we inside a string?
+ ((nth 3 pps)
+ (py-fill-string (nth 8 pps)))
+ ;; are we at the opening quote of a string, or in the indentation?
+ ((save-excursion
+ (forward-word 1)
+ (eq (py-in-literal) 'string))
+ (save-excursion
+ (py-fill-string (py-point 'boi))))
+ ;; are we at or after the closing quote of a string?
+ ((save-excursion
+ (backward-word 1)
+ (eq (py-in-literal) 'string))
+ (save-excursion
+ (py-fill-string (py-point 'boi))))
+ ;; otherwise use the default
+ (t
+ (fill-paragraph justify))))))
diff --git a/Objects/classobject.c b/Objects/classobject.c
index d9f7219..be7ba2d 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -5,6 +5,15 @@
#define TP_DESCR_GET(t) ((t)->tp_descr_get)
+/* Free list for method objects to safe malloc/free overhead
+ * The im_self element is used to chain the elements.
+ */
+static PyMethodObject *free_list;
+static int numfree = 0;
+#ifndef PyMethod_MAXFREELIST
+#define PyMethod_MAXFREELIST 256
+#endif
+
PyObject *
PyMethod_Function(PyObject *im)
{
@@ -30,8 +39,6 @@ PyMethod_Self(PyObject *im)
function.
*/
-static PyMethodObject *free_list;
-
PyObject *
PyMethod_New(PyObject *func, PyObject *self)
{
@@ -48,6 +55,7 @@ PyMethod_New(PyObject *func, PyObject *self)
if (im != NULL) {
free_list = (PyMethodObject *)(im->im_self);
PyObject_INIT(im, &PyMethod_Type);
+ numfree--;
}
else {
im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);
@@ -165,8 +173,14 @@ method_dealloc(register PyMethodObject *im)
PyObject_ClearWeakRefs((PyObject *)im);
Py_DECREF(im->im_func);
Py_XDECREF(im->im_self);
- im->im_self = (PyObject *)free_list;
- free_list = im;
+ if (numfree < PyMethod_MAXFREELIST) {
+ im->im_self = (PyObject *)free_list;
+ free_list = im;
+ numfree++;
+ }
+ else {
+ PyObject_GC_Del(im);
+ }
}
static PyObject *
@@ -375,7 +389,9 @@ PyMethod_Fini(void)
PyMethodObject *im = free_list;
free_list = (PyMethodObject *)(im->im_self);
PyObject_GC_Del(im);
+ numfree--;
}
+ assert(numfree == 0);
}
/* ------------------------------------------------------------------------
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 6a1938e..1bc7184 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -184,9 +184,11 @@ show_counts(void)
} while(0)
/* Dictionary reuse scheme to save calls to malloc, free, and memset */
-#define MAXFREEDICTS 80
-static PyDictObject *free_dicts[MAXFREEDICTS];
-static int num_free_dicts = 0;
+#ifndef PyDict_MAXFREELIST
+#define PyDict_MAXFREELIST 80
+#endif
+static PyDictObject *free_list[PyDict_MAXFREELIST];
+static int numfree = 0;
PyObject *
PyDict_New(void)
@@ -200,8 +202,8 @@ PyDict_New(void)
Py_AtExit(show_counts);
#endif
}
- if (num_free_dicts) {
- mp = free_dicts[--num_free_dicts];
+ if (numfree) {
+ mp = free_list[--numfree];
assert (mp != NULL);
assert (Py_TYPE(mp) == &PyDict_Type);
_Py_NewReference((PyObject *)mp);
@@ -897,8 +899,8 @@ dict_dealloc(register PyDictObject *mp)
}
if (mp->ma_table != mp->ma_smalltable)
PyMem_DEL(mp->ma_table);
- if (num_free_dicts < MAXFREEDICTS && Py_TYPE(mp) == &PyDict_Type)
- free_dicts[num_free_dicts++] = mp;
+ if (numfree < PyDict_MAXFREELIST && Py_TYPE(mp) == &PyDict_Type)
+ free_list[numfree++] = mp;
else
Py_TYPE(mp)->tp_free((PyObject *)mp);
Py_TRASHCAN_SAFE_END(mp)
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index deda244..658ce1d 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -401,14 +401,15 @@ static PyGetSetDef frame_getsetlist[] = {
call depth of more than 20 or 30 is probably already exceptional
unless the program contains run-away recursion. I hope.
- Later, MAXFREELIST was added to bound the # of frames saved on
+ Later, PyFrame_MAXFREELIST was added to bound the # of frames saved on
free_list. Else programs creating lots of cyclic trash involving
frames could provoke free_list into growing without bound.
*/
static PyFrameObject *free_list = NULL;
static int numfree = 0; /* number of frames currently in free_list */
-#define MAXFREELIST 200 /* max value for numfree */
+/* max value for numfree */
+#define PyFrame_MAXFREELIST 200
static void
frame_dealloc(PyFrameObject *f)
@@ -441,7 +442,7 @@ frame_dealloc(PyFrameObject *f)
co = f->f_code;
if (co->co_zombieframe == NULL)
co->co_zombieframe = f;
- else if (numfree < MAXFREELIST) {
+ else if (numfree < PyFrame_MAXFREELIST) {
++numfree;
f->f_back = free_list;
free_list = f;
diff --git a/Objects/listobject.c b/Objects/listobject.c
index a36a29e..cb0609a 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -64,18 +64,20 @@ list_resize(PyListObject *self, Py_ssize_t newsize)
}
/* Empty list reuse scheme to save calls to malloc and free */
-#define MAXFREELISTS 80
-static PyListObject *free_lists[MAXFREELISTS];
-static int num_free_lists = 0;
+#ifndef PyList_MAXFREELIST
+#define PyList_MAXFREELIST 80
+#endif
+static PyListObject *free_list[PyList_MAXFREELIST];
+static int numfree = 0;
void
PyList_Fini(void)
{
PyListObject *op;
- while (num_free_lists) {
- num_free_lists--;
- op = free_lists[num_free_lists];
+ while (numfree) {
+ numfree--;
+ op = free_list[numfree];
assert(PyList_CheckExact(op));
PyObject_GC_Del(op);
}
@@ -95,9 +97,9 @@ PyList_New(Py_ssize_t size)
/* Check for overflow */
if (nbytes / sizeof(PyObject *) != (size_t)size)
return PyErr_NoMemory();
- if (num_free_lists) {
- num_free_lists--;
- op = free_lists[num_free_lists];
+ if (numfree) {
+ numfree--;
+ op = free_list[numfree];
_Py_NewReference((PyObject *)op);
} else {
op = PyObject_GC_New(PyListObject, &PyList_Type);
@@ -265,8 +267,8 @@ list_dealloc(PyListObject *op)
}
PyMem_FREE(op->ob_item);
}
- if (num_free_lists < MAXFREELISTS && PyList_CheckExact(op))
- free_lists[num_free_lists++] = op;
+ if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op))
+ free_list[numfree++] = op;
else
Py_TYPE(op)->tp_free((PyObject *)op);
Py_TRASHCAN_SAFE_END(op)
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index 73e0790..7a82d89 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -4,7 +4,14 @@
#include "Python.h"
#include "structmember.h"
+/* Free list for method objects to safe malloc/free overhead
+ * The m_self element is used to chain the objects.
+ */
static PyCFunctionObject *free_list = NULL;
+static int numfree = 0;
+#ifndef PyCFunction_MAXFREELIST
+#define PyCFunction_MAXFREELIST 256
+#endif
PyObject *
PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
@@ -14,6 +21,7 @@ PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
if (op != NULL) {
free_list = (PyCFunctionObject *)(op->m_self);
PyObject_INIT(op, &PyCFunction_Type);
+ numfree--;
}
else {
op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type);
@@ -116,8 +124,14 @@ meth_dealloc(PyCFunctionObject *m)
_PyObject_GC_UNTRACK(m);
Py_XDECREF(m->m_self);
Py_XDECREF(m->m_module);
- m->m_self = (PyObject *)free_list;
- free_list = m;
+ if (numfree < PyCFunction_MAXFREELIST) {
+ m->m_self = (PyObject *)free_list;
+ free_list = m;
+ numfree++;
+ }
+ else {
+ PyObject_GC_Del(m);
+ }
}
static PyObject *
@@ -312,14 +326,16 @@ PyCFunction_Fini(void)
PyCFunctionObject *v = free_list;
free_list = (PyCFunctionObject *)(v->m_self);
PyObject_GC_Del(v);
+ numfree--;
}
+ assert(numfree == 0);
}
/* PyCFunction_New() is now just a macro that calls PyCFunction_NewEx(),
but it's part of the API so we need to keep a function around that
existing C extensions can call.
*/
-
+
#undef PyCFunction_New
PyAPI_FUNC(PyObject *) PyCFunction_New(PyMethodDef *, PyObject *);
diff --git a/Objects/setobject.c b/Objects/setobject.c
index c827434..fcc152a 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -52,9 +52,11 @@ _PySet_Dummy(void)
} while(0)
/* Reuse scheme to save calls to malloc, free, and memset */
-#define MAXFREESETS 80
-static PySetObject *free_sets[MAXFREESETS];
-static int num_free_sets = 0;
+#ifndef PySet_MAXFREELIST
+#define PySet_MAXFREELIST 80
+#endif
+static PySetObject *free_list[PySet_MAXFREELIST];
+static int numfree = 0;
/*
@@ -561,8 +563,8 @@ set_dealloc(PySetObject *so)
}
if (so->table != so->smalltable)
PyMem_DEL(so->table);
- if (num_free_sets < MAXFREESETS && PyAnySet_CheckExact(so))
- free_sets[num_free_sets++] = so;
+ if (numfree < PySet_MAXFREELIST && PyAnySet_CheckExact(so))
+ free_list[numfree++] = so;
else
Py_TYPE(so)->tp_free(so);
Py_TRASHCAN_SAFE_END(so)
@@ -975,9 +977,9 @@ make_new_set(PyTypeObject *type, PyObject *iterable)
}
/* create PySetObject structure */
- if (num_free_sets &&
+ if (numfree &&
(type == &PySet_Type || type == &PyFrozenSet_Type)) {
- so = free_sets[--num_free_sets];
+ so = free_list[--numfree];
assert (so != NULL && PyAnySet_CheckExact(so));
Py_TYPE(so) = type;
_Py_NewReference((PyObject *)so);
@@ -1045,9 +1047,9 @@ PySet_Fini(void)
{
PySetObject *so;
- while (num_free_sets) {
- num_free_sets--;
- so = free_sets[num_free_sets];
+ while (numfree) {
+ numfree--;
+ so = free_list[numfree];
PyObject_GC_Del(so);
}
Py_CLEAR(dummy);
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index c9d91e5..c212345 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -4,19 +4,19 @@
#include "Python.h"
/* Speed optimization to avoid frequent malloc/free of small tuples */
-#ifndef MAXSAVESIZE
-#define MAXSAVESIZE 20 /* Largest tuple to save on free list */
+#ifndef PyTuple_MAXSAVESIZE
+#define PyTuple_MAXSAVESIZE 20 /* Largest tuple to save on free list */
#endif
-#ifndef MAXSAVEDTUPLES
-#define MAXSAVEDTUPLES 2000 /* Maximum number of tuples of each size to save */
+#ifndef PyTuple_MAXFREELIST
+#define PyTuple_MAXFREELIST 2000 /* Maximum number of tuples of each size to save */
#endif
-#if MAXSAVESIZE > 0
-/* Entries 1 up to MAXSAVESIZE are free lists, entry 0 is the empty
+#if PyTuple_MAXSAVESIZE > 0
+/* Entries 1 up to PyTuple_MAXSAVESIZE are free lists, entry 0 is the empty
tuple () of which at most one instance will be allocated.
*/
-static PyTupleObject *free_tuples[MAXSAVESIZE];
-static int num_free_tuples[MAXSAVESIZE];
+static PyTupleObject *free_list[PyTuple_MAXSAVESIZE];
+static int numfree[PyTuple_MAXSAVESIZE];
#endif
#ifdef COUNT_ALLOCS
int fast_tuple_allocs;
@@ -32,18 +32,18 @@ PyTuple_New(register Py_ssize_t size)
PyErr_BadInternalCall();
return NULL;
}
-#if MAXSAVESIZE > 0
- if (size == 0 && free_tuples[0]) {
- op = free_tuples[0];
+#if PyTuple_MAXSAVESIZE > 0
+ if (size == 0 && free_list[0]) {
+ op = free_list[0];
Py_INCREF(op);
#ifdef COUNT_ALLOCS
tuple_zero_allocs++;
#endif
return (PyObject *) op;
}
- if (size < MAXSAVESIZE && (op = free_tuples[size]) != NULL) {
- free_tuples[size] = (PyTupleObject *) op->ob_item[0];
- num_free_tuples[size]--;
+ if (size < PyTuple_MAXSAVESIZE && (op = free_list[size]) != NULL) {
+ free_list[size] = (PyTupleObject *) op->ob_item[0];
+ numfree[size]--;
#ifdef COUNT_ALLOCS
fast_tuple_allocs++;
#endif
@@ -71,10 +71,10 @@ PyTuple_New(register Py_ssize_t size)
}
for (i=0; i < size; i++)
op->ob_item[i] = NULL;
-#if MAXSAVESIZE > 0
+#if PyTuple_MAXSAVESIZE > 0
if (size == 0) {
- free_tuples[0] = op;
- ++num_free_tuples[0];
+ free_list[0] = op;
+ ++numfree[0];
Py_INCREF(op); /* extra INCREF so that this is never freed */
}
#endif
@@ -167,14 +167,14 @@ tupledealloc(register PyTupleObject *op)
i = len;
while (--i >= 0)
Py_XDECREF(op->ob_item[i]);
-#if MAXSAVESIZE > 0
- if (len < MAXSAVESIZE &&
- num_free_tuples[len] < MAXSAVEDTUPLES &&
+#if PyTuple_MAXSAVESIZE > 0
+ if (len < PyTuple_MAXSAVESIZE &&
+ numfree[len] < PyTuple_MAXFREELIST &&
Py_TYPE(op) == &PyTuple_Type)
{
- op->ob_item[0] = (PyObject *) free_tuples[len];
- num_free_tuples[len]++;
- free_tuples[len] = op;
+ op->ob_item[0] = (PyObject *) free_list[len];
+ numfree[len]++;
+ free_list[len] = op;
goto done; /* return */
}
#endif
@@ -756,16 +756,16 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
void
PyTuple_Fini(void)
{
-#if MAXSAVESIZE > 0
+#if PyTuple_MAXSAVESIZE > 0
int i;
- Py_XDECREF(free_tuples[0]);
- free_tuples[0] = NULL;
+ Py_XDECREF(free_list[0]);
+ free_list[0] = NULL;
- for (i = 1; i < MAXSAVESIZE; i++) {
+ for (i = 1; i < PyTuple_MAXSAVESIZE; i++) {
PyTupleObject *p, *q;
- p = free_tuples[i];
- free_tuples[i] = NULL;
+ p = free_list[i];
+ free_list[i] = NULL;
while (p) {
q = p;
p = (PyTupleObject *)(p->ob_item[0]);
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 1b35d4e..4f0de1e 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -54,7 +54,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* Limit for the Unicode object free list */
-#define MAX_UNICODE_FREELIST_SIZE 1024
+#define PyUnicode_MAXFREELIST 1024
/* Limit for the Unicode object free list stay alive optimization.
@@ -62,7 +62,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
all objects on the free list having a size less than this
limit. This reduces malloc() overhead for small Unicode objects.
- At worst this will result in MAX_UNICODE_FREELIST_SIZE *
+ At worst this will result in PyUnicode_MAXFREELIST *
(sizeof(PyUnicodeObject) + KEEPALIVE_SIZE_LIMIT +
malloc()-overhead) bytes of unused garbage.
@@ -106,8 +106,8 @@ extern "C" {
static PyObject *interned;
/* Free list for Unicode objects */
-static PyUnicodeObject *unicode_freelist;
-static int unicode_freelist_size;
+static PyUnicodeObject *free_list;
+static int numfree;
/* The empty Unicode object is shared to improve performance. */
static PyUnicodeObject *unicode_empty;
@@ -313,10 +313,10 @@ PyUnicodeObject *_PyUnicode_New(Py_ssize_t length)
}
/* Unicode freelist & memory allocation */
- if (unicode_freelist) {
- unicode = unicode_freelist;
- unicode_freelist = *(PyUnicodeObject **)unicode;
- unicode_freelist_size--;
+ if (free_list) {
+ unicode = free_list;
+ free_list = *(PyUnicodeObject **)unicode;
+ numfree--;
if (unicode->str) {
/* Keep-Alive optimization: we only upsize the buffer,
never downsize it. */
@@ -386,7 +386,7 @@ void unicode_dealloc(register PyUnicodeObject *unicode)
}
if (PyUnicode_CheckExact(unicode) &&
- unicode_freelist_size < MAX_UNICODE_FREELIST_SIZE) {
+ numfree < PyUnicode_MAXFREELIST) {
/* Keep-Alive optimization */
if (unicode->length >= KEEPALIVE_SIZE_LIMIT) {
PyMem_DEL(unicode->str);
@@ -398,9 +398,9 @@ void unicode_dealloc(register PyUnicodeObject *unicode)
unicode->defenc = NULL;
}
/* Add to free list */
- *(PyUnicodeObject **)unicode = unicode_freelist;
- unicode_freelist = unicode;
- unicode_freelist_size++;
+ *(PyUnicodeObject **)unicode = free_list;
+ free_list = unicode;
+ numfree++;
}
else {
PyMem_DEL(unicode->str);
@@ -8033,7 +8033,7 @@ unicode_zfill(PyUnicodeObject *self, PyObject *args)
static PyObject*
unicode_freelistsize(PyUnicodeObject *self)
{
- return PyLong_FromLong(unicode_freelist_size);
+ return PyLong_FromLong(numfree);
}
#endif
@@ -9090,8 +9090,8 @@ void _PyUnicode_Init(void)
};
/* Init the implementation */
- unicode_freelist = NULL;
- unicode_freelist_size = 0;
+ free_list = NULL;
+ numfree = 0;
unicode_empty = _PyUnicode_New(0);
if (!unicode_empty)
return;
@@ -9127,7 +9127,7 @@ _PyUnicode_Fini(void)
}
}
- for (u = unicode_freelist; u != NULL;) {
+ for (u = free_list; u != NULL;) {
PyUnicodeObject *v = u;
u = *(PyUnicodeObject **)u;
if (v->str)
@@ -9135,8 +9135,8 @@ _PyUnicode_Fini(void)
Py_XDECREF(v->defenc);
PyObject_Del(v);
}
- unicode_freelist = NULL;
- unicode_freelist_size = 0;
+ free_list = NULL;
+ numfree = 0;
}
void
diff --git a/Python/compile.c b/Python/compile.c
index b256198..35ec10a 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -652,11 +652,16 @@ compiler_next_instr(struct compiler *c, basicblock *b)
return b->b_iused++;
}
-/* Set the i_lineno member of the instruction at offse off if the
- line number for the current expression/statement (?) has not
+/* Set the i_lineno member of the instruction at offset off if the
+ line number for the current expression/statement has not
already been set. If it has been set, the call has no effect.
- Every time a new node is b
+ The line number is reset in the following cases:
+ - when entering a new scope
+ - on each statement
+ - on each expression that start a new line
+ - before the "except" clause
+ - before the "for" and "while" expressions
*/
static void
@@ -1750,9 +1755,8 @@ compiler_for(struct compiler *c, stmt_ty s)
VISIT(c, expr, s->v.For.iter);
ADDOP(c, GET_ITER);
compiler_use_next_block(c, start);
- /* XXX(nnorwitz): is there a better way to handle this?
- for loops are special, we want to be able to trace them
- each time around, so we need to set an extra line number. */
+ /* for expressions must be traced on each iteration,
+ so we need to set an extra line number. */
c->u->u_lineno_set = 0;
ADDOP_JREL(c, FOR_ITER, cleanup);
VISIT(c, expr, s->v.For.target);
@@ -1799,6 +1803,9 @@ compiler_while(struct compiler *c, stmt_ty s)
if (!compiler_push_fblock(c, LOOP, loop))
return 0;
if (constant == -1) {
+ /* while expressions must be traced on each iteration,
+ so we need to set an extra line number. */
+ c->u->u_lineno_set = 0;
VISIT(c, expr, s->v.While.test);
ADDOP_JREL(c, JUMP_IF_FALSE, anchor);
ADDOP(c, POP_TOP);
@@ -1979,8 +1986,8 @@ compiler_try_except(struct compiler *c, stmt_ty s)
s->v.TryExcept.handlers, i);
if (!handler->type && i < n-1)
return compiler_error(c, "default 'except:' must be last");
- c->u->u_lineno_set = 0;
- c->u->u_lineno = handler->lineno;
+ c->u->u_lineno_set = 0;
+ c->u->u_lineno = handler->lineno;
except = compiler_new_block(c);
if (except == NULL)
return 0;
@@ -3762,10 +3769,7 @@ assemble_lnotab(struct assembler *a, struct instr *i)
assert(d_bytecode >= 0);
assert(d_lineno >= 0);
- /* XXX(nnorwitz): is there a better way to handle this?
- for loops are special, we want to be able to trace them
- each time around, so we need to set an extra line number. */
- if (d_lineno == 0 && i->i_opcode != FOR_ITER)
+ if(d_bytecode == 0 && d_lineno == 0)
return 1;
if (d_bytecode > 255) {