From 25bb783c030cd1c4f13297f3e2e1b6246d3f0a0c Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Fri, 11 Jan 2008 16:17:00 +0000 Subject: Merged revisions 59883-59920 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r59887 | neal.norwitz | 2008-01-10 06:42:58 +0100 (Thu, 10 Jan 2008) | 1 line Reword entry, not sure I made it much better though. ........ r59888 | andrew.kuchling | 2008-01-10 14:37:12 +0100 (Thu, 10 Jan 2008) | 1 line Check for fd of -1 to save fsync() and fstat() call ........ r59891 | thomas.heller | 2008-01-10 19:45:40 +0100 (Thu, 10 Jan 2008) | 1 line Reflow a paragraph, and fix a typo. ........ r59892 | raymond.hettinger | 2008-01-10 20:15:10 +0100 (Thu, 10 Jan 2008) | 1 line Examples for named tuple subclassing should include __slots__ ........ r59895 | raymond.hettinger | 2008-01-10 21:37:12 +0100 (Thu, 10 Jan 2008) | 1 line Clarify how to add a field to a named tuple. ........ r59896 | amaury.forgeotdarc | 2008-01-10 22:59:42 +0100 (Thu, 10 Jan 2008) | 12 lines Closing issue1761. Surprising behaviour of the "$" regexp: it matches the end of the string, AND just before the newline at the end of the string:: re.sub('$', '#', 'foo\n') == 'foo#\n#' Python is consistent with Perl and the pcre library, so we just document it. Guido prefers "\Z" to match only the end of the string. ........ r59898 | raymond.hettinger | 2008-01-11 00:00:01 +0100 (Fri, 11 Jan 2008) | 1 line Neaten-up the named tuple docs ........ r59900 | raymond.hettinger | 2008-01-11 01:23:13 +0100 (Fri, 11 Jan 2008) | 1 line Run doctests on the collections module ........ r59903 | raymond.hettinger | 2008-01-11 02:25:54 +0100 (Fri, 11 Jan 2008) | 1 line Doctest results return a named tuple for readability ........ r59904 | raymond.hettinger | 2008-01-11 03:12:33 +0100 (Fri, 11 Jan 2008) | 1 line Comment-out missing constant (from rev 59819) ........ r59905 | raymond.hettinger | 2008-01-11 03:24:13 +0100 (Fri, 11 Jan 2008) | 1 line Have Decimal.as_tuple return a named tuple. ........ r59906 | raymond.hettinger | 2008-01-11 04:04:50 +0100 (Fri, 11 Jan 2008) | 1 line Let most inspect functions return named tuples ........ r59907 | raymond.hettinger | 2008-01-11 04:20:54 +0100 (Fri, 11 Jan 2008) | 1 line Improve usability of the SequenceMatcher by returning named tuples describing match ranges. ........ r59909 | thomas.heller | 2008-01-11 09:04:03 +0100 (Fri, 11 Jan 2008) | 1 line Add an important missing blank. ........ r59910 | georg.brandl | 2008-01-11 10:19:11 +0100 (Fri, 11 Jan 2008) | 2 lines Guard definition of TIPC_SUB_CANCEL with an #ifdef. ........ r59911 | georg.brandl | 2008-01-11 10:20:58 +0100 (Fri, 11 Jan 2008) | 2 lines News entries for rev. 5990[567]. ........ r59912 | georg.brandl | 2008-01-11 10:55:53 +0100 (Fri, 11 Jan 2008) | 2 lines Documentation for r5990[3567]. ........ r59913 | thomas.heller | 2008-01-11 13:41:39 +0100 (Fri, 11 Jan 2008) | 4 lines The sqlite3 dll, when compiled in debug mode, must be linked with /MDd to use the debug runtime library. Further, the dll will be named sqlite3_d.dll. ........ r59919 | thomas.heller | 2008-01-11 16:38:46 +0100 (Fri, 11 Jan 2008) | 6 lines Revert revision 59913, because it was wrong: The sqlite3 dll, when compiled in debug mode, must be linked with /MDd to use the debug runtime library. Further, the dll will be named sqlite3_d.dll. ........ r59920 | christian.heimes | 2008-01-11 16:42:29 +0100 (Fri, 11 Jan 2008) | 1 line Removed unused variable ........ --- Doc/glossary.rst | 7 +++ Doc/library/collections.rst | 23 +++++---- Doc/library/decimal.rst | 6 ++- Doc/library/difflib.rst | 5 +- Doc/library/doctest.rst | 5 +- Doc/library/inspect.rst | 22 ++++---- Doc/library/re.rst | 4 +- Lib/collections.py | 9 +++- Lib/decimal.py | 8 ++- Lib/difflib.py | 19 ++++--- Lib/doctest.py | 27 +++++----- Lib/inspect.py | 30 ++++++++--- Lib/test/test_collections.py | 6 ++- Lib/test/test_doctest.py | 116 +++++++++++++++++++++---------------------- Lib/test/test_pyclbr.py | 6 +-- Lib/test/test_re.py | 12 +++++ Modules/mmapmodule.c | 6 ++- Modules/socketmodule.c | 5 +- PCbuild/build_tkinter.py | 2 +- PCbuild/readme.txt | 10 ++-- 20 files changed, 203 insertions(+), 125 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 6d12d0f..194fbd9 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -327,6 +327,13 @@ Glossary mutable Mutable objects can change their value but keep their :func:`id`. See also :term:`immutable`. + + named tuple + A tuple subclass whose elements also are accessible as attributes via + fixed names (the class name and field names are indicated in the + individual documentation of a named tuple type, like ``TestResults(failed, + attempted)``). Named tuple classes are created by + :func:`collections.namedtuple`. namespace The place where a variable is stored. Namespaces are implemented as diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index fdfdefe..f1a8fff 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -397,8 +397,8 @@ they add the ability to access fields by name instead of position index. method which lists the tuple contents in a ``name=value`` format. The *fieldnames* are a single string with each fieldname separated by whitespace - and/or commas (for example 'x y' or 'x, y'). Alternatively, *fieldnames* - can be a sequence of strings (such as ['x', 'y']). + and/or commas, for example ``'x y'`` or ``'x, y'``. Alternatively, *fieldnames* + can be a sequence of strings such as ``['x', 'y']``. Any valid Python identifier may be used for a fieldname except for names starting with an underscore. Valid identifiers consist of letters, digits, @@ -406,7 +406,7 @@ they add the ability to access fields by name instead of position index. a :mod:`keyword` such as *class*, *for*, *return*, *global*, *pass*, *print*, or *raise*. - If *verbose* is true, will print the class definition. + If *verbose* is true, the class definition is printed just before being built. Named tuple instances do not have per-instance dictionaries, so they are lightweight and require no more memory than regular tuples. @@ -533,7 +533,7 @@ function:: >>> getattr(p, 'x') 11 -To cast a dictionary to a named tuple, use the double-star-operator [#]_:: +To convert a dictionary to a named tuple, use the double-star-operator [#]_:: >>> d = {'x': 11, 'y': 22} >>> Point(**d) @@ -544,23 +544,24 @@ functionality with a subclass. Here is how to add a calculated field and a fixed-width print format:: >>> class Point(namedtuple('Point', 'x y')): + ... __slots__ = () ... @property ... def hypot(self): ... return (self.x ** 2 + self.y ** 2) ** 0.5 ... def __str__(self): - ... return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot) + ... return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot) - >>> for p in Point(3,4), Point(14,5), Point(9./7,6): + >>> for p in Point(3, 4), Point(14, 5/7.): ... print(p) - Point: x= 3.000 y= 4.000 hypot= 5.000 - Point: x=14.000 y= 5.000 hypot=14.866 - Point: x= 1.286 y= 6.000 hypot= 6.136 + Point: x= 3.000 y= 4.000 hypot= 5.000 + Point: x=14.000 y= 0.714 hypot=14.018 Another use for subclassing is to replace performance critcal methods with -faster versions that bypass error-checking and that localize variable access:: +faster versions that bypass error-checking:: class Point(namedtuple('Point', 'x y')): + __slots__ = () _make = classmethod(tuple.__new__) def _replace(self, _map=map, **kwds): return self._make(_map(kwds.get, ('x', 'y'), self)) @@ -569,7 +570,7 @@ faster versions that bypass error-checking and that localize variable access:: Subclassing is not useful for adding new, stored fields. Instead, simply create a new named tuple type from the :attr:`_fields` attribute:: - >>> Pixel = namedtuple('Pixel', Point._fields + Color._fields) + >>> Point3D = namedtuple('Point3D', Point._fields + ('z',)) Default values can be implemented by using :meth:`_replace` to customize a prototype instance:: diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index e29e4ea..fbd6f43 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -328,7 +328,11 @@ also have a number of specialized methods: .. method:: Decimal.as_tuple() - Return a tuple representation of the number: ``(sign, digit_tuple, exponent)``. + Return a :term:`named tuple` representation of the number: + ``DecimalTuple(sign, digits, exponent)``. + + .. versionchanged:: 2.6 + Use a named tuple. .. method:: Decimal.canonical() diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst index 34dbcfd..7e61aa9 100644 --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -336,7 +336,7 @@ use :meth:`set_seq2` to set the commonly used sequence once and call Find longest matching block in ``a[alo:ahi]`` and ``b[blo:bhi]``. - If *isjunk* was omitted or ``None``, :meth:`get_longest_match` returns ``(i, j, + If *isjunk* was omitted or ``None``, :meth:`find_longest_match` returns ``(i, j, k)`` such that ``a[i:i+k]`` is equal to ``b[j:j+k]``, where ``alo <= i <= i+k <= ahi`` and ``blo <= j <= j+k <= bhi``. For all ``(i', j', k')`` meeting those conditions, the additional conditions ``k >= k'``, ``i <= i'``, and if ``i == @@ -365,6 +365,9 @@ use :meth:`set_seq2` to set the commonly used sequence once and call If no blocks match, this returns ``(alo, blo, 0)``. + .. versionchanged:: 2.6 + This method returns a :term:`named tuple` ``Match(a, b, size)``. + .. method:: SequenceMatcher.get_matching_blocks() diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst index 04bc219..ce8b9f0 100644 --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -1436,11 +1436,14 @@ DocTestRunner objects .. method:: DocTestRunner.summarize([verbose]) Print a summary of all the test cases that have been run by this DocTestRunner, - and return a tuple ``(failure_count, test_count)``. + and return a :term:`named tuple` ``TestResults(failed, attempted)``. The optional *verbose* argument controls how detailed the summary is. If the verbosity is not specified, then the :class:`DocTestRunner`'s verbosity is used. + .. versionchanged:: 2.6 + Use a named tuple. + .. _doctest-outputchecker: diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index e5008f6..5daa496 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -188,7 +188,8 @@ attributes: .. function:: getmoduleinfo(path) - Return a tuple of values that describe how Python will interpret the file + Returns a :term:`named tuple` ``ModuleInfo(name, suffix, mode, + module_type)`` of values that describe how Python will interpret the file identified by *path* if it is a module, or ``None`` if it would not be identified as a module. The return tuple is ``(name, suffix, mode, mtype)``, where *name* is the name of the module without the name of any enclosing @@ -377,8 +378,9 @@ Classes and functions .. function:: getargspec(func) - Get the names and default values of a function's arguments. A tuple of four - things is returned: ``(args, varargs, varkw, defaults)``. *args* is a list of + Get the names and default values of a function's arguments. A + :term:`named tuple` ``ArgSpec(args, varargs, keywords, + defaults)`` is returned. *args* is a list of the argument names. *varargs* and *varkw* are the names of the ``*`` and ``**`` arguments or ``None``. *defaults* is a tuple of default argument values or None if there are no default arguments; if this tuple has *n* @@ -391,10 +393,10 @@ Classes and functions .. function:: getfullargspec(func) - Get the names and default values of a function's arguments. A tuple of seven - things is returned: + Get the names and default values of a function's arguments. A :term:`named tuple` + is returned: - ``(args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations)`` + ``FullArgSpec(args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations)`` *args* is a list of the argument names. *varargs* and *varkw* are the names of the ``*`` and ``**`` arguments or ``None``. *defaults* is an n-tuple of @@ -408,8 +410,8 @@ Classes and functions .. function:: getargvalues(frame) - Get information about arguments passed into a particular frame. A tuple of four - things is returned: ``(args, varargs, varkw, locals)``. *args* is a list of the + Get information about arguments passed into a particular frame. A :term:`named tuple` + ``ArgInfo(args, varargs, keywords, locals)`` is returned. *args* is a list of the argument names (it may contain nested lists). *varargs* and *varkw* are the names of the ``*`` and ``**`` arguments or ``None``. *locals* is the locals dictionary of the given frame. @@ -476,8 +478,8 @@ line. .. function:: getframeinfo(frame[, context]) - Get information about a frame or traceback object. A 5-tuple is returned, the - last five elements of the frame's frame record. + Get information about a frame or traceback object. A :term:`named tuple` + ``Traceback(filename, lineno, function, code_context, index)`` is returned. .. function:: getouterframes(frame[, context]) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 49c5215..7de088a 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -98,7 +98,9 @@ The special characters are: string, and in :const:`MULTILINE` mode also matches before a newline. ``foo`` matches both 'foo' and 'foobar', while the regular expression ``foo$`` matches only 'foo'. More interestingly, searching for ``foo.$`` in ``'foo1\nfoo2\n'`` - matches 'foo2' normally, but 'foo1' in :const:`MULTILINE` mode. + matches 'foo2' normally, but 'foo1' in :const:`MULTILINE` mode; searching for + a single ``$`` in ``'foo\n'`` will find two (empty) matches: one just before + the newline, and one at the end of the string. ``'*'`` Causes the resulting RE to match 0 or more repetitions of the preceding RE, as diff --git a/Lib/collections.py b/Lib/collections.py index e1e9d11..78f92ce 100644 --- a/Lib/collections.py +++ b/Lib/collections.py @@ -117,23 +117,28 @@ if __name__ == '__main__': # test and demonstrate ability to override methods class Point(namedtuple('Point', 'x y')): + __slots__ = () @property def hypot(self): return (self.x ** 2 + self.y ** 2) ** 0.5 def __str__(self): - return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot) + return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot) - for p in Point(3,4), Point(14,5), Point(9./7,6): + for p in Point(3, 4), Point(14, 5/7.): print (p) class Point(namedtuple('Point', 'x y')): 'Point class with optimized _make() and _replace() without error-checking' + __slots__ = () _make = classmethod(tuple.__new__) def _replace(self, _map=map, **kwds): return self._make(_map(kwds.get, ('x', 'y'), self)) print(Point(11, 22)._replace(x=100)) + Point3D = namedtuple('Point3D', Point._fields + ('z',)) + print(Point3D.__doc__) + import doctest TestResults = namedtuple('TestResults', 'failed attempted') print(TestResults(*doctest.testmod())) diff --git a/Lib/decimal.py b/Lib/decimal.py index 1f5ff12..434930a 100644 --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -137,6 +137,12 @@ __all__ = [ import numbers as _numbers import copy as _copy +try: + from collections import namedtuple as _namedtuple + DecimalTuple = _namedtuple('DecimalTuple', 'sign digits exponent') +except ImportError: + DecimalTuple = lambda *args: args + # Rounding ROUND_DOWN = 'ROUND_DOWN' ROUND_HALF_UP = 'ROUND_HALF_UP' @@ -841,7 +847,7 @@ class Decimal(_numbers.Real, _numbers.Inexact): To show the internals exactly as they are. """ - return (self._sign, tuple(map(int, self._int)), self._exp) + return DecimalTuple(self._sign, tuple(map(int, self._int)), self._exp) def __repr__(self): """Represents the number as an instance of Decimal.""" diff --git a/Lib/difflib.py b/Lib/difflib.py index 82e3319..361be6e 100644 --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -30,9 +30,12 @@ Class HtmlDiff: __all__ = ['get_close_matches', 'ndiff', 'restore', 'SequenceMatcher', 'Differ','IS_CHARACTER_JUNK', 'IS_LINE_JUNK', 'context_diff', - 'unified_diff', 'HtmlDiff'] + 'unified_diff', 'HtmlDiff', 'Match'] import heapq +from collections import namedtuple as _namedtuple + +Match = _namedtuple('Match', 'a b size') def _calculate_ratio(matches, length): if length: @@ -363,7 +366,7 @@ class SequenceMatcher: >>> s = SequenceMatcher(None, " abcd", "abcd abcd") >>> s.find_longest_match(0, 5, 0, 9) - (0, 4, 5) + Match(a=0, b=4, size=5) If isjunk is defined, first the longest matching block is determined as above, but with the additional restriction that no @@ -379,13 +382,13 @@ class SequenceMatcher: >>> s = SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd") >>> s.find_longest_match(0, 5, 0, 9) - (1, 0, 4) + Match(a=1, b=0, size=4) If no blocks match, return (alo, blo, 0). >>> s = SequenceMatcher(None, "ab", "c") >>> s.find_longest_match(0, 2, 0, 1) - (0, 0, 0) + Match(a=0, b=0, size=0) """ # CAUTION: stripping common prefix or suffix would be incorrect. @@ -452,7 +455,7 @@ class SequenceMatcher: a[besti+bestsize] == b[bestj+bestsize]: bestsize = bestsize + 1 - return besti, bestj, bestsize + return Match(besti, bestj, bestsize) def get_matching_blocks(self): """Return list of triples describing matching subsequences. @@ -469,8 +472,8 @@ class SequenceMatcher: triple with n==0. >>> s = SequenceMatcher(None, "abxcd", "abcd") - >>> s.get_matching_blocks() - [(0, 0, 2), (3, 2, 2), (5, 4, 0)] + >>> list(s.get_matching_blocks()) + [Match(a=0, b=0, size=2), Match(a=3, b=2, size=2), Match(a=5, b=4, size=0)] """ if self.matching_blocks is not None: @@ -523,7 +526,7 @@ class SequenceMatcher: non_adjacent.append( (la, lb, 0) ) self.matching_blocks = non_adjacent - return self.matching_blocks + return map(Match._make, self.matching_blocks) def get_opcodes(self): """Return list of 5-tuples describing how to turn a into b. diff --git a/Lib/doctest.py b/Lib/doctest.py index 4a2da32..b5fa574 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -99,6 +99,9 @@ import sys, traceback, inspect, linecache, os, re import unittest, difflib, pdb, tempfile import warnings from io import StringIO +from collections import namedtuple + +TestResults = namedtuple('TestResults', 'failed attempted') # There are 4 basic classes: # - Example: a pair, plus an intra-docstring line number. @@ -1024,10 +1027,10 @@ class DocTestRunner: >>> tests.sort(key = lambda test: test.name) >>> for test in tests: ... print(test.name, '->', runner.run(test)) - _TestClass -> (0, 2) - _TestClass.__init__ -> (0, 2) - _TestClass.get -> (0, 2) - _TestClass.square -> (0, 1) + _TestClass -> TestResults(failed=0, attempted=2) + _TestClass.__init__ -> TestResults(failed=0, attempted=2) + _TestClass.get -> TestResults(failed=0, attempted=2) + _TestClass.square -> TestResults(failed=0, attempted=1) The `summarize` method prints a summary of all the test cases that have been run by the runner, and returns an aggregated `(f, t)` @@ -1042,7 +1045,7 @@ class DocTestRunner: 7 tests in 4 items. 7 passed and 0 failed. Test passed. - (0, 7) + TestResults(failed=0, attempted=7) The aggregated number of tried examples and failed examples is also available via the `tries` and `failures` attributes: @@ -1285,7 +1288,7 @@ class DocTestRunner: # Record and return the number of failures and tries. self.__record_outcome(test, failures, tries) - return failures, tries + return TestResults(failures, tries) def __record_outcome(self, test, f, t): """ @@ -1417,7 +1420,7 @@ class DocTestRunner: print("***Test Failed***", totalf, "failures.") elif verbose: print("Test passed.") - return totalf, totalt + return TestResults(totalf, totalt) #///////////////////////////////////////////////////////////////// # Backward compatibility cruft to maintain doctest.master. @@ -1688,7 +1691,7 @@ class DebugRunner(DocTestRunner): ... ''', {}, 'foo', 'foo.py', 0) >>> runner.run(test) - (0, 1) + TestResults(failed=0, attempted=1) >>> test.globs {} @@ -1818,7 +1821,7 @@ def testmod(m=None, name=None, globs=None, verbose=None, else: master.merge(runner) - return runner.failures, runner.tries + return TestResults(runner.failures, runner.tries) def testfile(filename, module_relative=True, name=None, package=None, globs=None, verbose=None, report=True, optionflags=0, @@ -1939,7 +1942,7 @@ def testfile(filename, module_relative=True, name=None, package=None, else: master.merge(runner) - return runner.failures, runner.tries + return TestResults(runner.failures, runner.tries) def run_docstring_examples(f, globs, verbose=False, name="NoName", compileflags=None, optionflags=0): @@ -1998,7 +2001,7 @@ class Tester: (f,t) = self.testrunner.run(test) if self.verbose: print(f, "of", t, "examples failed in string", name) - return (f,t) + return TestResults(f,t) def rundoc(self, object, name=None, module=None): f = t = 0 @@ -2007,7 +2010,7 @@ class Tester: for test in tests: (f2, t2) = self.testrunner.run(test) (f,t) = (f+f2, t+t2) - return (f,t) + return TestResults(f,t) def rundict(self, d, name, module=None): import types diff --git a/Lib/inspect.py b/Lib/inspect.py index c0db4bc..074754f 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -31,6 +31,7 @@ __date__ = '1 Jan 2001' import sys, os, types, re, dis, imp, tokenize, linecache from operator import attrgetter +from collections import namedtuple # ----------------------------------------------------------- type-checking def ismodule(object): @@ -208,6 +209,8 @@ def getmembers(object, predicate=None): results.sort() return results +Attribute = namedtuple('Attribute', 'name kind defining_class object') + def classify_class_attrs(cls): """Return list of attribute-descriptor tuples. @@ -274,7 +277,7 @@ def classify_class_attrs(cls): else: kind = "data" - result.append((name, kind, homecls, obj)) + result.append(Attribute(name, kind, homecls, obj)) return result @@ -362,6 +365,8 @@ def getfile(object): raise TypeError('arg is not a module, class, method, ' 'function, traceback, frame, or code object') +ModuleInfo = namedtuple('ModuleInfo', 'name suffix mode module_type') + def getmoduleinfo(path): """Get the module name, suffix, mode, and module type for a given file.""" filename = os.path.basename(path) @@ -370,7 +375,7 @@ def getmoduleinfo(path): suffixes.sort() # try longest suffixes first, in case they overlap for neglen, suffix, mode, mtype in suffixes: if filename[neglen:] == suffix: - return filename[:neglen], suffix, mode, mtype + return ModuleInfo(filename[:neglen], suffix, mode, mtype) def getmodulename(path): """Return the module name for a given file, or None.""" @@ -668,6 +673,8 @@ def getclasstree(classes, unique=0): # These constants are from Python's compile.h. CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8 +Arguments = namedtuple('Arguments', 'args, varargs, varkw') + def getargs(co): """Get information about the arguments accepted by a code object. @@ -676,7 +683,7 @@ def getargs(co): lists. Keyword-only arguments are appended. 'varargs' and 'varkw' are the names of the * and ** arguments or None.""" args, varargs, kwonlyargs, varkw = _getfullargs(co) - return args + kwonlyargs, varargs, varkw + return Arguments(args + kwonlyargs, varargs, varkw) def _getfullargs(co): """Get information about the arguments accepted by a code object. @@ -706,6 +713,9 @@ def _getfullargs(co): varkw = co.co_varnames[nargs] return args, varargs, kwonlyargs, varkw + +ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults') + def getargspec(func): """Get the names and default values of a function's arguments. @@ -725,7 +735,10 @@ def getargspec(func): if kwonlyargs or ann: raise ValueError("Function has keyword-only arguments or annotations" ", use getfullargspec() API which can support them") - return (args, varargs, varkw, defaults) + return ArgSpec(args, varargs, varkw, defaults) + +FullArgSpec = namedtuple('FullArgSpec', + 'args, varargs, varkw, defaults, kwonlyargs, kwdefaults, annotations') def getfullargspec(func): """Get the names and default values of a function's arguments. @@ -747,9 +760,11 @@ def getfullargspec(func): if not isfunction(func): raise TypeError('arg is not a Python function') args, varargs, kwonlyargs, varkw = _getfullargs(func.__code__) - return (args, varargs, varkw, func.__defaults__, + return FullArgSpec(args, varargs, varkw, func.__defaults__, kwonlyargs, func.__kwdefaults__, func.__annotations__) +ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals') + def getargvalues(frame): """Get information about arguments passed into a particular frame. @@ -859,6 +874,9 @@ def formatargvalues(args, varargs, varkw, locals, return '(' + ', '.join(specs) + ')' # -------------------------------------------------- stack frame extraction + +Traceback = namedtuple('Traceback', 'filename lineno function code_context index') + def getframeinfo(frame, context=1): """Get information about a frame or traceback object. @@ -890,7 +908,7 @@ def getframeinfo(frame, context=1): else: lines = index = None - return (filename, lineno, frame.f_code.co_name, lines, index) + return Traceback(filename, lineno, frame.f_code.co_name, lines, index) def getlineno(frame): """Get the line number from a frame object, allowing for optimization.""" diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index d8cf72e..77af0fb 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -1,6 +1,6 @@ """Unit tests for collections.py.""" -import unittest +import unittest, doctest from test import test_support from collections import namedtuple from collections import Hashable, Iterable, Iterator @@ -316,10 +316,12 @@ class TestCollectionABCs(unittest.TestCase): self.failUnless(issubclass(sample, MutableSequence)) self.failIf(issubclass(str, MutableSequence)) +import doctest, collections +NamedTupleDocs = doctest.DocTestSuite(module=collections) def test_main(verbose=None): import collections as CollectionsModule - test_classes = [TestNamedTuple, TestOneTrickPonyABCs, TestCollectionABCs] + test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs] test_support.run_unittest(*test_classes) test_support.run_doctest(CollectionsModule, verbose) diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index db370b1..07e2542 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -658,7 +658,7 @@ given DocTest case in a given namespace (globs). It returns a tuple of tried tests. >>> doctest.DocTestRunner(verbose=False).run(test) - (0, 3) + TestResults(failed=0, attempted=3) If any example produces incorrect output, then the test runner reports the failure and proceeds to the next example: @@ -695,7 +695,7 @@ the failure and proceeds to the next example: Expecting: 6 ok - (1, 3) + TestResults(failed=1, attempted=3) """ def verbose_flag(): r""" The `verbose` flag makes the test runner generate more detailed @@ -726,7 +726,7 @@ output: Expecting: 6 ok - (0, 3) + TestResults(failed=0, attempted=3) If the `verbose` flag is unspecified, then the output will be verbose iff `-v` appears in sys.argv: @@ -737,7 +737,7 @@ iff `-v` appears in sys.argv: >>> # If -v does not appear in sys.argv, then output isn't verbose. >>> sys.argv = ['test'] >>> doctest.DocTestRunner().run(test) - (0, 3) + TestResults(failed=0, attempted=3) >>> # If -v does appear in sys.argv, then output is verbose. >>> sys.argv = ['test', '-v'] @@ -756,7 +756,7 @@ iff `-v` appears in sys.argv: Expecting: 6 ok - (0, 3) + TestResults(failed=0, attempted=3) >>> # Restore sys.argv >>> sys.argv = old_argv @@ -780,7 +780,7 @@ replaced with any other string: ... ''' >>> test = doctest.DocTestFinder().find(f)[0] >>> doctest.DocTestRunner(verbose=False).run(test) - (0, 2) + TestResults(failed=0, attempted=2) An example may not generate output before it raises an exception; if it does, then the traceback message will not be recognized as @@ -805,7 +805,7 @@ unexpected exception: Exception raised: ... ZeroDivisionError: integer division or modulo by zero - (1, 2) + TestResults(failed=1, attempted=2) Exception messages may contain newlines: @@ -819,7 +819,7 @@ Exception messages may contain newlines: ... ''' >>> test = doctest.DocTestFinder().find(f)[0] >>> doctest.DocTestRunner(verbose=False).run(test) - (0, 1) + TestResults(failed=0, attempted=1) If an exception is expected, but an exception with the wrong type or message is raised, then it is reported as a failure: @@ -844,7 +844,7 @@ message is raised, then it is reported as a failure: Traceback (most recent call last): ... ValueError: message - (1, 1) + TestResults(failed=1, attempted=1) However, IGNORE_EXCEPTION_DETAIL can be used to allow a mismatch in the detail: @@ -857,7 +857,7 @@ detail: ... ''' >>> test = doctest.DocTestFinder().find(f)[0] >>> doctest.DocTestRunner(verbose=False).run(test) - (0, 1) + TestResults(failed=0, attempted=1) But IGNORE_EXCEPTION_DETAIL does not allow a mismatch in the exception type: @@ -881,7 +881,7 @@ But IGNORE_EXCEPTION_DETAIL does not allow a mismatch in the exception type: Traceback (most recent call last): ... ValueError: message - (1, 1) + TestResults(failed=1, attempted=1) If an exception is raised but not expected, then it is reported as an unexpected exception: @@ -902,7 +902,7 @@ unexpected exception: Traceback (most recent call last): ... ZeroDivisionError: integer division or modulo by zero - (1, 1) + TestResults(failed=1, attempted=1) """ def optionflags(): r""" Tests of `DocTestRunner`'s option flag handling. @@ -921,7 +921,7 @@ and 1/0: >>> # Without the flag: >>> test = doctest.DocTestFinder().find(f)[0] >>> doctest.DocTestRunner(verbose=False).run(test) - (0, 1) + TestResults(failed=0, attempted=1) >>> # With the flag: >>> test = doctest.DocTestFinder().find(f)[0] @@ -936,7 +936,7 @@ and 1/0: 1 Got: True - (1, 1) + TestResults(failed=1, attempted=1) The DONT_ACCEPT_BLANKLINE flag disables the match between blank lines and the '' marker: @@ -947,7 +947,7 @@ and the '' marker: >>> # Without the flag: >>> test = doctest.DocTestFinder().find(f)[0] >>> doctest.DocTestRunner(verbose=False).run(test) - (0, 1) + TestResults(failed=0, attempted=1) >>> # With the flag: >>> test = doctest.DocTestFinder().find(f)[0] @@ -966,7 +966,7 @@ and the '' marker: a b - (1, 1) + TestResults(failed=1, attempted=1) The NORMALIZE_WHITESPACE flag causes all sequences of whitespace to be treated as equal: @@ -987,13 +987,13 @@ treated as equal: 3 Got: 1 2 3 - (1, 1) + TestResults(failed=1, attempted=1) >>> # With the flag: >>> test = doctest.DocTestFinder().find(f)[0] >>> flags = doctest.NORMALIZE_WHITESPACE >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) - (0, 1) + TestResults(failed=0, attempted=1) An example from the docs: >>> print(list(range(20))) #doctest: +NORMALIZE_WHITESPACE @@ -1018,13 +1018,13 @@ output to match any substring in the actual output: [0, 1, 2, ..., 14] Got: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] - (1, 1) + TestResults(failed=1, attempted=1) >>> # With the flag: >>> test = doctest.DocTestFinder().find(f)[0] >>> flags = doctest.ELLIPSIS >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) - (0, 1) + TestResults(failed=0, attempted=1) ... also matches nothing: @@ -1109,7 +1109,7 @@ and actual outputs to be displayed using a unified diff: e f g - (1, 1) + TestResults(failed=1, attempted=1) >>> # With the flag: >>> test = doctest.DocTestFinder().find(f)[0] @@ -1131,7 +1131,7 @@ and actual outputs to be displayed using a unified diff: f g -h - (1, 1) + TestResults(failed=1, attempted=1) The REPORT_CDIFF flag causes failures that involve multi-line expected and actual outputs to be displayed using a context diff: @@ -1163,7 +1163,7 @@ and actual outputs to be displayed using a context diff: + e f g - (1, 1) + TestResults(failed=1, attempted=1) The REPORT_NDIFF flag causes failures to use the difflib.Differ algorithm @@ -1188,7 +1188,7 @@ marking, as well as interline differences. ? ^ + a b c d e f g h i j k l m ? + ++ ^ - (1, 1) + TestResults(failed=1, attempted=1) The REPORT_ONLY_FIRST_FAILURE supresses result output after the first failing example: @@ -1218,7 +1218,7 @@ failing example: 200 Got: 2 - (3, 5) + TestResults(failed=3, attempted=5) However, output from `report_start` is not supressed: @@ -1241,7 +1241,7 @@ However, output from `report_start` is not supressed: 200 Got: 2 - (3, 5) + TestResults(failed=3, attempted=5) For the purposes of REPORT_ONLY_FIRST_FAILURE, unexpected exceptions count as failures: @@ -1270,7 +1270,7 @@ count as failures: Exception raised: ... ValueError: 2 - (3, 5) + TestResults(failed=3, attempted=5) New option flags can also be registered, via register_optionflag(). Here we reach into doctest's internals a bit. @@ -1319,7 +1319,7 @@ example with a comment of the form ``# doctest: +OPTION``: [0, 1, ..., 9] Got: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - (1, 2) + TestResults(failed=1, attempted=2) To turn an option off for an example, follow that example with a comment of the form ``# doctest: -OPTION``: @@ -1344,7 +1344,7 @@ comment of the form ``# doctest: -OPTION``: [0, 1, ..., 9] Got: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - (1, 2) + TestResults(failed=1, attempted=2) Option directives affect only the example that they appear with; they do not change the options for surrounding examples: @@ -1378,7 +1378,7 @@ do not change the options for surrounding examples: [0, 1, ..., 9] Got: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - (2, 3) + TestResults(failed=2, attempted=3) Multiple options may be modified by a single option directive. They may be separated by whitespace, commas, or both: @@ -1401,7 +1401,7 @@ may be separated by whitespace, commas, or both: [0, 1, ..., 9] Got: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - (1, 2) + TestResults(failed=1, attempted=2) >>> def f(x): r''' ... >>> print(list(range(10))) # Should fail @@ -1421,7 +1421,7 @@ may be separated by whitespace, commas, or both: [0, 1, ..., 9] Got: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - (1, 2) + TestResults(failed=1, attempted=2) >>> def f(x): r''' ... >>> print(list(range(10))) # Should fail @@ -1441,7 +1441,7 @@ may be separated by whitespace, commas, or both: [0, 1, ..., 9] Got: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - (1, 2) + TestResults(failed=1, attempted=2) The option directive may be put on the line following the source, as long as a continuation prompt is used: @@ -1453,7 +1453,7 @@ long as a continuation prompt is used: ... ''' >>> test = doctest.DocTestFinder().find(f)[0] >>> doctest.DocTestRunner(verbose=False).run(test) - (0, 1) + TestResults(failed=0, attempted=1) For examples with multi-line source, the option directive may appear at the end of any line: @@ -1469,7 +1469,7 @@ at the end of any line: ... ''' >>> test = doctest.DocTestFinder().find(f)[0] >>> doctest.DocTestRunner(verbose=False).run(test) - (0, 2) + TestResults(failed=0, attempted=2) If more than one line of an example with multi-line source has an option directive, then they are combined: @@ -1482,7 +1482,7 @@ option directive, then they are combined: ... ''' >>> test = doctest.DocTestFinder().find(f)[0] >>> doctest.DocTestRunner(verbose=False).run(test) - (0, 1) + TestResults(failed=0, attempted=1) It is an error to have a comment of the form ``# doctest:`` that is *not* followed by words of the form ``+OPTION`` or ``-OPTION``, where @@ -1616,7 +1616,7 @@ def test_pdb_set_trace(): (Pdb) print(x) 42 (Pdb) continue - (0, 2) + TestResults(failed=0, attempted=2) You can also put pdb.set_trace in a function called from a test: @@ -1652,7 +1652,7 @@ def test_pdb_set_trace(): (Pdb) print(x) 1 (Pdb) continue - (0, 2) + TestResults(failed=0, attempted=2) During interactive debugging, source code is shown, even for doctest examples: @@ -1709,7 +1709,7 @@ def test_pdb_set_trace(): Expected nothing Got: 9 - (1, 3) + TestResults(failed=1, attempted=3) """ def test_pdb_set_trace_nested(): @@ -1795,7 +1795,7 @@ def test_pdb_set_trace_nested(): (Pdb) print(foo) *** NameError: NameError("name 'foo' is not defined",) (Pdb) continue - (0, 2) + TestResults(failed=0, attempted=2) """ def test_DocTestSuite(): @@ -2156,7 +2156,7 @@ calling module. The return value is (#failures, #tests). 1 items had failures: 1 of 2 in test_doctest.txt ***Test Failed*** 1 failures. - (1, 2) + TestResults(failed=1, attempted=2) >>> doctest.master = None # Reset master. (Note: we'll be clearing doctest.master after each call to @@ -2167,7 +2167,7 @@ Globals may be specified with the `globs` and `extraglobs` parameters: >>> globs = {'favorite_color': 'blue'} >>> doctest.testfile('test_doctest.txt', globs=globs) - (0, 2) + TestResults(failed=0, attempted=2) >>> doctest.master = None # Reset master. >>> extraglobs = {'favorite_color': 'red'} @@ -2185,7 +2185,7 @@ Globals may be specified with the `globs` and `extraglobs` parameters: 1 items had failures: 1 of 2 in test_doctest.txt ***Test Failed*** 1 failures. - (1, 2) + TestResults(failed=1, attempted=2) >>> doctest.master = None # Reset master. The file may be made relative to a given module or package, using the @@ -2193,7 +2193,7 @@ optional `module_relative` parameter: >>> doctest.testfile('test_doctest.txt', globs=globs, ... module_relative='test') - (0, 2) + TestResults(failed=0, attempted=2) >>> doctest.master = None # Reset master. Verbosity can be increased with the optional `verbose` paremter: @@ -2219,7 +2219,7 @@ Verbosity can be increased with the optional `verbose` paremter: 2 tests in 1 items. 2 passed and 0 failed. Test passed. - (0, 2) + TestResults(failed=0, attempted=2) >>> doctest.master = None # Reset master. The name of the test may be specified with the optional `name` @@ -2230,7 +2230,7 @@ parameter: ********************************************************************** File "...", line 6, in newname ... - (1, 2) + TestResults(failed=1, attempted=2) >>> doctest.master = None # Reset master. The summary report may be supressed with the optional `report` @@ -2245,7 +2245,7 @@ parameter: Exception raised: ... NameError: name 'favorite_color' is not defined - (1, 2) + TestResults(failed=1, attempted=2) >>> doctest.master = None # Reset master. The optional keyword argument `raise_on_error` can be used to raise an @@ -2277,11 +2277,11 @@ using the optional keyword argument `encoding`: 1 items had failures: 2 of 2 in test_doctest4.txt ***Test Failed*** 2 failures. - (2, 2) + TestResults(failed=2, attempted=2) >>> doctest.master = None # Reset master. >>> doctest.testfile('test_doctest4.txt', encoding='utf-8') - (0, 2) + TestResults(failed=0, attempted=2) >>> doctest.master = None # Reset master. """ @@ -2311,15 +2311,15 @@ Expected: 42 Got: 84 -(1, 2) +TestResults(failed=1, attempted=2) >>> t.runstring(">>> x = x * 2\n>>> print(x)\n84\n", 'example2') -(0, 2) +TestResults(failed=0, attempted=2) >>> t.summarize() ********************************************************************** 1 items had failures: 1 of 2 in XYZ ***Test Failed*** 1 failures. -(1, 4) +TestResults(failed=1, attempted=4) >>> t.summarize(verbose=1) 1 items passed all tests: 2 tests in example2 @@ -2329,7 +2329,7 @@ Got: 4 tests in 2 items. 3 passed and 1 failed. ***Test Failed*** 1 failures. -(1, 4) +TestResults(failed=1, attempted=4) """ def old_test2(): r""" @@ -2353,7 +2353,7 @@ def old_test2(): r""" 3 ok 0 of 2 examples failed in string Example - (0, 2) + TestResults(failed=0, attempted=2) """ def old_test3(): r""" @@ -2366,7 +2366,7 @@ def old_test3(): r""" ... return 32 ... >>> t.rundoc(_f) # expect 0 failures in 1 example - (0, 1) + TestResults(failed=0, attempted=1) """ def old_test4(): """ @@ -2396,19 +2396,19 @@ def old_test4(): """ >>> from doctest import Tester >>> t = Tester(globs={}, verbose=0) >>> t.rundict(m1.__dict__, "rundict_test", m1) # f2 and g2 and h2 skipped - (0, 4) + TestResults(failed=0, attempted=4) Once more, not excluding stuff outside m1: >>> t = Tester(globs={}, verbose=0) >>> t.rundict(m1.__dict__, "rundict_test_pvt") # None are skipped. - (0, 8) + TestResults(failed=0, attempted=8) The exclusion of objects from outside the designated module is meant to be invoked automagically by testmod. >>> doctest.testmod(m1, verbose=False) - (0, 4) + TestResults(failed=0, attempted=4) """ ###################################################################### diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index b88cb7e..5d46db1 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -40,7 +40,7 @@ class PyclbrTest(TestCase): if key in ignore: return if key not in obj: print("***",key, file=sys.stderr) - self.failUnless(key in obj) + self.failUnless(key in obj, "%r in %r" % (key, obj)) def assertEqualsOrIgnored(self, a, b, ignore): ''' succeed iff a == b or a in ignore or b in ignore ''' @@ -140,9 +140,9 @@ class PyclbrTest(TestCase): def test_easy(self): self.checkModule('pyclbr') - self.checkModule('doctest') + self.checkModule('doctest', ignore=("TestResults",)) self.checkModule('rfc822') - self.checkModule('difflib') + self.checkModule('difflib', ignore=("Match",)) def test_decorators(self): # XXX: See comment in pyclbr_input.py for a test that would fail diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 866f598..28e508c 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -661,6 +661,18 @@ class ReTests(unittest.TestCase): q = p.match(upper_char) self.assertNotEqual(q, None) + def test_dollar_matches_twice(self): + "$ matches the end of string, and just before the terminating \n" + pattern = re.compile('$') + self.assertEqual(pattern.sub('#', 'a\nb\n'), 'a\nb#\n#') + self.assertEqual(pattern.sub('#', 'a\nb\nc'), 'a\nb\nc#') + self.assertEqual(pattern.sub('#', '\n'), '#\n#') + + pattern = re.compile('$', re.MULTILINE) + self.assertEqual(pattern.sub('#', 'a\nb\n' ), 'a#\nb#\n#' ) + self.assertEqual(pattern.sub('#', 'a\nb\nc'), 'a#\nb#\nc#') + self.assertEqual(pattern.sub('#', '\n'), '#\n#') + def run_re_tests(): from test.re_tests import benchmarks, tests, SUCCEED, FAIL, SYNTAX_ERROR diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 84f909e..8302767 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -980,9 +980,11 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict) #ifdef HAVE_FSTAT # ifdef __VMS /* on OpenVMS we must ensure that all bytes are written to the file */ - fsync(fd); + if (fd != -1) { + fsync(fd); + } # endif - if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) { + if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) { if (map_size == 0) { map_size = st.st_size; } else if ((size_t)offset + (size_t)map_size > st.st_size) { diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index dc05108..7ad96d3 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -4097,7 +4097,7 @@ See the socket module for documentation."); PyMODINIT_FUNC init_socket(void) { - PyObject *m, *has_ipv6, *tmp; + PyObject *m, *has_ipv6; if (!os_init()) return; @@ -4354,7 +4354,10 @@ init_socket(void) /* for subscriptions */ PyModule_AddIntConstant(m, "TIPC_SUB_PORTS", TIPC_SUB_PORTS); PyModule_AddIntConstant(m, "TIPC_SUB_SERVICE", TIPC_SUB_SERVICE); +#ifdef TIPC_SUB_CANCEL + /* doesn't seem to be available everywhere */ PyModule_AddIntConstant(m, "TIPC_SUB_CANCEL", TIPC_SUB_CANCEL); +#endif PyModule_AddIntConstant(m, "TIPC_WAIT_FOREVER", TIPC_WAIT_FOREVER); PyModule_AddIntConstant(m, "TIPC_PUBLISHED", TIPC_PUBLISHED); PyModule_AddIntConstant(m, "TIPC_WITHDRAWN", TIPC_WITHDRAWN); diff --git a/PCbuild/build_tkinter.py b/PCbuild/build_tkinter.py index a7205d0..574d768 100644 --- a/PCbuild/build_tkinter.py +++ b/PCbuild/build_tkinter.py @@ -25,7 +25,7 @@ ROOT = os.path.abspath(os.path.join(here, par, par)) # Windows 2000 compatibility: WINVER 0x0500 # http://msdn2.microsoft.com/en-us/library/aa383745.aspx NMAKE = ('nmake /nologo /f %s ' - 'COMPILERFLAGS=\"-DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -DNTDDI_VERSION=NTDDI_WIN2KSP4\"' + 'COMPILERFLAGS=\"-DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -DNTDDI_VERSION=NTDDI_WIN2KSP4\" ' '%s %s') def nmake(makefile, command="", **kw): diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 00b7de0..764ab8a 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -117,7 +117,7 @@ _tkinter Build with build_tkinter.py --------------------------- The PCbuild directory contains a Python script which automates all - steps. Run the script in a Visual Studio 2009 command prompt with + steps. Run the script in a Visual Studio 2008 command prompt with python build_tkinter.py Win32 @@ -312,9 +312,11 @@ Edition. Profile Guided Optimization --------------------------- -The solution has two configurations for PGO. The PGInstrument configuration -must be build first. The PGInstrument binaries are lniked against a profiling -library and contain extra debug information. The PGUpdate configuration takes the profiling data and generates optimized binaries. +The solution has two configurations for PGO. The PGInstrument +configuration must be build first. The PGInstrument binaries are +lniked against a profiling library and contain extra debug +information. The PGUpdate configuration takes the profiling data and +generates optimized binaries. The build_pgo.bat script automates the creation of optimized binaries. It creates the PGI files, runs the unit test suite or PyBench with the PGI -- cgit v0.12