Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Python: Checkins

cpython (merge 3.3 -> default): merge with 3.3

 

 

First page Previous page 1 2 Next page Last page  View All Python checkins RSS feed   Index | Next | Previous | View Threaded


python-checkins at python

May 12, 2013, 3:47 AM

Post #1 of 34 (186 views)
Permalink
cpython (merge 3.3 -> default): merge with 3.3

http://hg.python.org/cpython/rev/ca133fab2f8e
changeset: 83743:ca133fab2f8e
parent: 83731:e98cf2cec516
parent: 83741:19a5fbb924b1
user: Georg Brandl <georg [at] python>
date: Sun May 12 12:08:05 2013 +0200
summary:
merge with 3.3

files:
Lib/test/test_sax.py | 31 +++++++++++++++++++++++++++++
Lib/xml/sax/saxutils.py | 5 ++++
Misc/NEWS | 9 ++++++++
3 files changed, 45 insertions(+), 0 deletions(-)


diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py
--- a/Lib/test/test_sax.py
+++ b/Lib/test/test_sax.py
@@ -15,6 +15,7 @@
from xml.sax.handler import feature_namespaces
from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
from io import BytesIO, StringIO
+import codecs
import os.path
import shutil
from test import support
@@ -538,6 +539,34 @@
def getvalue(self):
return b''.join(self)

+class StreamWriterXmlgenTest(XmlgenTest, unittest.TestCase):
+ def ioclass(self):
+ raw = BytesIO()
+ writer = codecs.getwriter('ascii')(raw, 'xmlcharrefreplace')
+ writer.getvalue = raw.getvalue
+ return writer
+
+ def xml(self, doc, encoding='iso-8859-1'):
+ return ('<?xml version="1.0" encoding="%s"?>\n%s' %
+ (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
+
+class StreamReaderWriterXmlgenTest(XmlgenTest, unittest.TestCase):
+ fname = support.TESTFN + '-codecs'
+
+ def ioclass(self):
+ writer = codecs.open(self.fname, 'w', encoding='ascii',
+ errors='xmlcharrefreplace', buffering=0)
+ self.addCleanup(support.unlink, self.fname)
+ writer.getvalue = self.getvalue
+ return writer
+
+ def getvalue(self):
+ with open(self.fname, 'rb') as f:
+ return f.read()
+
+ def xml(self, doc, encoding='iso-8859-1'):
+ return ('<?xml version="1.0" encoding="%s"?>\n%s' %
+ (encoding, doc)).encode('ascii', 'xmlcharrefreplace')

start = b'<?xml version="1.0" encoding="iso-8859-1"?>\n'

@@ -946,6 +975,8 @@
StringXmlgenTest,
BytesXmlgenTest,
WriterXmlgenTest,
+ StreamWriterXmlgenTest,
+ StreamReaderWriterXmlgenTest,
ExpatReaderTest,
ErrorReportingTest,
XmlReaderTest)
diff --git a/Lib/xml/sax/saxutils.py b/Lib/xml/sax/saxutils.py
--- a/Lib/xml/sax/saxutils.py
+++ b/Lib/xml/sax/saxutils.py
@@ -5,6 +5,7 @@

import os, urllib.parse, urllib.request
import io
+import codecs
from . import handler
from . import xmlreader

@@ -77,6 +78,10 @@
# use a text writer as is
return out

+ if isinstance(out, (codecs.StreamWriter, codecs.StreamReaderWriter)):
+ # use a codecs stream writer as is
+ return out
+
# wrap a binary writer with TextIOWrapper
if isinstance(out, io.RawIOBase):
# Keep the original file open when the TextIOWrapper is
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -91,6 +91,9 @@
Library
-------

+- Issue #17915: Fix interoperability of xml.sax with file objects returned by
+ codecs.open().
+
- Issue #16601: Restarting iteration over tarfile no more continues from where
it left off. Patch by Michael Birtwell.

@@ -280,6 +283,12 @@
- Issue #17692: test_sqlite now works with unittest test discovery.
Patch by Zachary Ware.

+
+Documentation
+-------------
+
+- Issue #15940: Specify effect of locale on time functions.
+
- Issue #6696: add documentation for the Profile objects, and improve
profile/cProfile docs. Patch by Tom Pinckney.


--
Repository URL: http://hg.python.org/cpython


python-checkins at python

May 12, 2013, 3:47 AM

Post #2 of 34 (182 views)
Permalink
cpython (merge 3.3 -> default): merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/47752459be5b
changeset: 83746:47752459be5b
parent: 83744:5400e8fbc1de
parent: 83745:6c5a3d194a10
user: Georg Brandl <georg [at] python>
date: Sun May 12 12:37:12 2013 +0200
summary:
merge with 3.3

files:
Doc/install/index.rst | 5 +
Doc/library/venv.rst | 4 +
Lib/distutils/dist.py | 14 ++++-
Lib/distutils/tests/test_dist.py | 64 +++++++++++++++++++-
Misc/NEWS | 3 +
5 files changed, 87 insertions(+), 3 deletions(-)


diff --git a/Doc/install/index.rst b/Doc/install/index.rst
--- a/Doc/install/index.rst
+++ b/Doc/install/index.rst
@@ -645,6 +645,11 @@
the Distutils are the only ones you can use.) See section :ref:`inst-config-files`
for details.

+.. note:: When a :ref:`virtual environment <venv-def>` is activated, any options
+ that change the installation path will be ignored from all distutils configuration
+ files to prevent inadvertently installing projects outside of the virtual
+ environment.
+
.. XXX need some Windows examples---when would custom installation schemes be
needed on those platforms?

diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst
--- a/Doc/library/venv.rst
+++ b/Doc/library/venv.rst
@@ -57,6 +57,10 @@
:attr:`sys.exec_prefix` is the same as :attr:`sys.base_exec_prefix` (they
all point to a non-venv Python installation).

+ When a venv is active, any options that change the installation path will be
+ ignored from all distutils configuration files to prevent projects being
+ inadvertently installed outside of the virtual environment.
+

API
---
diff --git a/Lib/distutils/dist.py b/Lib/distutils/dist.py
--- a/Lib/distutils/dist.py
+++ b/Lib/distutils/dist.py
@@ -343,6 +343,18 @@
def parse_config_files(self, filenames=None):
from configparser import ConfigParser

+ # Ignore install directory options if we have a venv
+ if sys.prefix != sys.base_prefix:
+ ignore_options = [.
+ 'install-base', 'install-platbase', 'install-lib',
+ 'install-platlib', 'install-purelib', 'install-headers',
+ 'install-scripts', 'install-data', 'prefix', 'exec-prefix',
+ 'home', 'user', 'root']
+ else:
+ ignore_options = []
+
+ ignore_options = frozenset(ignore_options)
+
if filenames is None:
filenames = self.find_config_files()

@@ -359,7 +371,7 @@
opt_dict = self.get_option_dict(section)

for opt in options:
- if opt != '__name__':
+ if opt != '__name__' and opt not in ignore_options:
val = parser.get(section,opt)
opt = opt.replace('-', '_')
opt_dict[opt] = (filename, val)
diff --git a/Lib/distutils/tests/test_dist.py b/Lib/distutils/tests/test_dist.py
--- a/Lib/distutils/tests/test_dist.py
+++ b/Lib/distutils/tests/test_dist.py
@@ -6,6 +6,8 @@
import warnings
import textwrap

+from unittest import mock
+
from distutils.dist import Distribution, fix_help_options
from distutils.cmd import Command

@@ -18,7 +20,7 @@

user_options = [
("sample-option=", "S", "help text"),
- ]
+ ]

def initialize_options(self):
self.sample_option = None
@@ -77,6 +79,64 @@
self.assertIsInstance(cmd, test_dist)
self.assertEqual(cmd.sample_option, "sometext")

+ def test_venv_install_options(self):
+ sys.argv.append("install")
+ self.addCleanup(os.unlink, TESTFN)
+
+ fakepath = '/somedir'
+
+ with open(TESTFN, "w") as f:
+ print(("[install]\n"
+ "install-base = {0}\n"
+ "install-platbase = {0}\n"
+ "install-lib = {0}\n"
+ "install-platlib = {0}\n"
+ "install-purelib = {0}\n"
+ "install-headers = {0}\n"
+ "install-scripts = {0}\n"
+ "install-data = {0}\n"
+ "prefix = {0}\n"
+ "exec-prefix = {0}\n"
+ "home = {0}\n"
+ "user = {0}\n"
+ "root = {0}").format(fakepath), file=f)
+
+ # Base case: Not in a Virtual Environment
+ with mock.patch.multiple(sys, prefix='/a', base_prefix='/a') as values:
+ d = self.create_distribution([TESTFN])
+
+ option_tuple = (TESTFN, fakepath)
+
+ result_dict = {
+ 'install_base': option_tuple,
+ 'install_platbase': option_tuple,
+ 'install_lib': option_tuple,
+ 'install_platlib': option_tuple,
+ 'install_purelib': option_tuple,
+ 'install_headers': option_tuple,
+ 'install_scripts': option_tuple,
+ 'install_data': option_tuple,
+ 'prefix': option_tuple,
+ 'exec_prefix': option_tuple,
+ 'home': option_tuple,
+ 'user': option_tuple,
+ 'root': option_tuple,
+ }
+
+ self.assertEqual(
+ sorted(d.command_options.get('install').keys()),
+ sorted(result_dict.keys()))
+
+ for (key, value) in d.command_options.get('install').items():
+ self.assertEqual(value, result_dict[key])
+
+ # Test case: In a Virtual Environment
+ with mock.patch.multiple(sys, prefix='/a', base_prefix='/b') as values:
+ d = self.create_distribution([TESTFN])
+
+ for key in result_dict.keys():
+ self.assertNotIn(key, d.command_options.get('install', {}))
+
def test_command_packages_configfile(self):
sys.argv.append("build")
self.addCleanup(os.unlink, TESTFN)
@@ -304,7 +364,7 @@
os.environ['HOME'] = temp_dir
files = dist.find_config_files()
self.assertIn(user_filename, files,
- '%r not found in %r' % (user_filename, files))
+ '%r not found in %r' % (user_filename, files))
finally:
os.remove(user_filename)

diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -91,6 +91,9 @@
Library
-------

+- Issue #17732: Ignore distutils.cfg options pertaining to install paths if a
+ virtual environment is active.
+
- Issue #17915: Fix interoperability of xml.sax with file objects returned by
codecs.open().


--
Repository URL: http://hg.python.org/cpython


python-checkins at python

May 12, 2013, 10:56 AM

Post #3 of 34 (182 views)
Permalink
cpython (merge 3.3 -> default): merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/2626a8bb7615
changeset: 83754:2626a8bb7615
parent: 83749:00afa5350f6a
parent: 83753:f4345201048f
user: Georg Brandl <georg [at] python>
date: Sun May 12 19:57:26 2013 +0200
summary:
merge with 3.3

files:
.hgtags | 1 +
PC/VS9.0/pyproject.vsprops | 2 +-
PCbuild/pyproject.props | 2 +-
PCbuild/readme.txt | 2 +-
Tools/buildbot/external-common.bat | 8 ++++----
5 files changed, 8 insertions(+), 7 deletions(-)


diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -113,3 +113,4 @@
bd8afb90ebf28ba4edc901d4a235f75e7bbc79fd v3.3.0
92c2cfb924055ce68c4f78f836dcfe688437ceb8 v3.3.1rc1
d9893d13c6289aa03d33559ec67f97dcbf5c9e3c v3.3.1
+d047928ae3f6314a13b6137051315453d0ae89b6 v3.3.2
diff --git a/PC/VS9.0/pyproject.vsprops b/PC/VS9.0/pyproject.vsprops
--- a/PC/VS9.0/pyproject.vsprops
+++ b/PC/VS9.0/pyproject.vsprops
@@ -62,7 +62,7 @@
/>
<UserMacro
Name="opensslDir"
- Value="$(externalsDir)\openssl-1.0.1d"
+ Value="$(externalsDir)\openssl-1.0.1e"
/>
<UserMacro
Name="tcltkDir"
diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props
--- a/PCbuild/pyproject.props
+++ b/PCbuild/pyproject.props
@@ -20,7 +20,7 @@
<sqlite3Dir>$(externalsDir)\sqlite-3.7.12</sqlite3Dir>
<bz2Dir>$(externalsDir)\bzip2-1.0.6</bz2Dir>
<lzmaDir>$(externalsDir)\xz-5.0.3</lzmaDir>
- <opensslDir>$(externalsDir)\openssl-1.0.1d</opensslDir>
+ <opensslDir>$(externalsDir)\openssl-1.0.1e</opensslDir>
<tcltkDir>$(externalsDir)\tcltk</tcltkDir>
<tcltk64Dir>$(externalsDir)\tcltk64</tcltk64Dir>
<tcltkLib>$(tcltkDir)\lib\tcl85.lib;$(tcltkDir)\lib\tk85.lib</tcltkLib>
diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt
--- a/PCbuild/readme.txt
+++ b/PCbuild/readme.txt
@@ -142,7 +142,7 @@

Get the source code through

- svn export http://svn.python.org/projects/external/openssl-1.0.1d
+ svn export http://svn.python.org/projects/external/openssl-1.0.1e

** NOTE: if you use the Tools\buildbot\external(-amd64).bat approach for
obtaining external sources then you don't need to manually get the source
diff --git a/Tools/buildbot/external-common.bat b/Tools/buildbot/external-common.bat
--- a/Tools/buildbot/external-common.bat
+++ b/Tools/buildbot/external-common.bat
@@ -14,7 +14,7 @@
@rem if exist tk8.4.16 rd /s/q tk8.4.16
@rem if exist tk-8.4.18.1 rd /s/q tk-8.4.18.1
@rem if exist db-4.4.20 rd /s/q db-4.4.20
- [at] re if exist openssl-1.0.1d rd /s/q openssl-1.0.1d
+@rem if exist openssl-1.0.1e rd /s/q openssl-1.0.1e
@rem if exist sqlite-3.7.12 rd /s/q sqlite-3.7.12

@rem bzip
@@ -24,9 +24,9 @@
)

@rem OpenSSL
-if not exist openssl-1.0.1d (
- rd /s/q openssl-1.0.1c
- svn export http://svn.python.org/projects/external/openssl-1.0.1d
+if not exist openssl-1.0.1e (
+ rd /s/q openssl-1.0.1d
+ svn export http://svn.python.org/projects/external/openssl-1.0.1e
)

@rem tcl/tk

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

May 13, 2013, 1:17 PM

Post #4 of 34 (171 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/2368f6f9963f
changeset: 83764:2368f6f9963f
parent: 83762:eeb89ebfa9b6
parent: 83763:c1383ddf7cb9
user: Terry Jan Reedy <tjreedy [at] udel>
date: Mon May 13 16:09:47 2013 -0400
summary:
Merge with 3.3

files:
Lib/idlelib/textView.py | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)


diff --git a/Lib/idlelib/textView.py b/Lib/idlelib/textView.py
--- a/Lib/idlelib/textView.py
+++ b/Lib/idlelib/textView.py
@@ -80,7 +80,8 @@
root=Tk()
root.title('textView test')
filename = './textView.py'
- text = open(filename, 'r').read()
+ with open(filename, 'r') as f:
+ text = f.read()
btn1 = Button(root, text='view_text',
command=lambda:view_text(root, 'view_text', text))
btn1.pack(side=LEFT)

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

May 16, 2013, 10:03 AM

Post #5 of 34 (171 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/5b89f1b09756
changeset: 83790:5b89f1b09756
parent: 83788:3ee61b048173
parent: 83789:d62f71bd2192
user: Brian Curtin <brian [at] python>
date: Thu May 16 12:03:40 2013 -0500
summary:
Merge with 3.3

files:
Misc/ACKS | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)


diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1161,6 +1161,7 @@
J. Sipprell
Kragen Sitaker
Michael Sloan
+Nick Sloan
Václav Šmilauer
Christopher Smith
Eric V. Smith

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

May 27, 2013, 6:34 PM

Post #6 of 34 (168 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/c5d4c041ab47
changeset: 83942:c5d4c041ab47
parent: 83940:2ea849fde22b
parent: 83941:24c3e7e08168
user: Terry Jan Reedy <tjreedy [at] udel>
date: Mon May 27 21:33:40 2013 -0400
summary:
Merge with 3.3

files:
Lib/idlelib/CallTips.py | 4 +-
Lib/idlelib/PathBrowser.py | 3 +-
Lib/idlelib/idle_test/@README.txt | 63 +++++++++++
Lib/idlelib/idle_test/__init__.py | 9 +
Lib/idlelib/idle_test/test_calltips.py | 11 +
Lib/idlelib/idle_test/test_pathbrowser.py | 12 ++
Lib/test/test_idle.py | 14 ++
Misc/ACKS | 1 +
Misc/NEWS | 3 +
9 files changed, 118 insertions(+), 2 deletions(-)


diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py
--- a/Lib/idlelib/CallTips.py
+++ b/Lib/idlelib/CallTips.py
@@ -264,4 +264,6 @@
print("%d of %d tests failed" % (num_fail, num_tests))

if __name__ == '__main__':
- main()
+ #main()
+ from unittest import main
+ main('idlelib.idle_test.test_calltips', verbosity=2, exit=False)
diff --git a/Lib/idlelib/PathBrowser.py b/Lib/idlelib/PathBrowser.py
--- a/Lib/idlelib/PathBrowser.py
+++ b/Lib/idlelib/PathBrowser.py
@@ -95,4 +95,5 @@
mainloop()

if __name__ == "__main__":
- main()
+ from unittest import main
+ main('idlelib.idle_test.test_pathbrowser', verbosity=2, exit=False)
diff --git a/Lib/idlelib/idle_test/@README.txt b/Lib/idlelib/idle_test/@README.txt
new file mode 100644
--- /dev/null
+++ b/Lib/idlelib/idle_test/@README.txt
@@ -0,0 +1,63 @@
+README FOR IDLE TESTS IN IDLELIB.IDLE_TEST
+
+The idle directory, idlelib, has over 60 xyz.py files. The idle_test
+subdirectory should contain a test_xyy.py for each one. (For test modules,
+make 'xyz' lower case.) Each should start with the following cut-paste
+template, with the blanks after after '.'. 'as', and '_' filled in.
+---
+import unittest
+import idlelib. as
+
+class Test_(unittest.TestCase):
+
+ def test_(self):
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2, exit=2)
+---
+Idle tests are run with unittest; do not use regrtest's test_main.
+
+Once test_xyy is written, the following should go at the end of xyy.py,
+with xyz (lowercased) added after 'test_'.
+---
+if __name__ == "__main__":
+ import unittest
+ unittest.main('idlelib.idle_test.test_', verbosity=2, exit=False)
+---
+
+In Idle, pressing F5 in an editor window with either xyz.py or test_xyz.py
+loaded will then run the test with the version of Python running Idle and
+tracebacks will appear in the Shell window. The options are appropriate for
+developers running (as opposed to importing) either type of file during
+development: verbosity=2 lists all test_y methods; exit=False avoids a
+spurious sys.exit traceback when running in Idle. The following command
+lines also run test_xyz.py
+
+python -m idlelib.xyz # With the capitalization of the xyz module
+python -m unittest -v idlelib.idle_test.test_xyz
+
+To run all idle tests either interactively ('>>>', with unittest imported)
+or from a command line, use one of the following.
+
+>>> unittest.main('idlelib.idle_test', verbosity=2, exit=False)
+python -m unittest -v idlelib.idle_test
+python -m test.test_idle
+python -m test test_idle
+
+The idle tests are 'discovered' in idlelib.idle_test.__init__.load_tests,
+which is also imported into test.test_idle. Normally, neither file should be
+changed when working on individual test modules. The last command runs runs
+unittest indirectly through regrtest. The same happens when the entire test
+suite is run with 'python -m test'. So it must work for buildbots to stay green.
+
+To run an individual Testcase or test method, extend the
+dotted name given to unittest on the command line.
+
+python -m unittest -v idlelib.idle_test.text_xyz.Test_case.test_meth
+
+To disable test/test_idle.py, there are at least two choices.
+a. Comment out 'load_tests' line, no no tests are discovered (simple and safe);
+Running no tests passes, so there is no indication that nothing was run.
+b.Before that line, make module an unexpected skip for regrtest with
+import unittest; raise unittest.SkipTest('skip for buildbots')
+When run directly with unittest, this causes a normal exit and traceback.
\ No newline at end of file
diff --git a/Lib/idlelib/idle_test/__init__.py b/Lib/idlelib/idle_test/__init__.py
new file mode 100644
--- /dev/null
+++ b/Lib/idlelib/idle_test/__init__.py
@@ -0,0 +1,9 @@
+from os.path import dirname
+
+def load_tests(loader, standard_tests, pattern):
+ this_dir = dirname(__file__)
+ top_dir = dirname(dirname(this_dir))
+ package_tests = loader.discover(start_dir=this_dir, pattern='test*.py',
+ top_level_dir=top_dir)
+ standard_tests.addTests(package_tests)
+ return standard_tests
diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py
new file mode 100644
--- /dev/null
+++ b/Lib/idlelib/idle_test/test_calltips.py
@@ -0,0 +1,11 @@
+import unittest
+import idlelib.CallTips as ct
+
+class Test_get_entity(unittest.TestCase):
+ def test_bad_entity(self):
+ self.assertIsNone(ct.get_entity('1/0'))
+ def test_good_entity(self):
+ self.assertIs(ct.get_entity('int'), int)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2, exit=False)
diff --git a/Lib/idlelib/idle_test/test_pathbrowser.py b/Lib/idlelib/idle_test/test_pathbrowser.py
new file mode 100644
--- /dev/null
+++ b/Lib/idlelib/idle_test/test_pathbrowser.py
@@ -0,0 +1,12 @@
+import unittest
+import idlelib.PathBrowser as PathBrowser
+
+class PathBrowserTest(unittest.TestCase):
+
+ def test_DirBrowserTreeItem(self):
+ # Issue16226 - make sure that getting a sublist works
+ d = PathBrowser.DirBrowserTreeItem('')
+ d.GetSubList()
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2, exit=False)
diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_idle.py
@@ -0,0 +1,14 @@
+# Skip test if tkinter wasn't built or idlelib was deleted.
+from test.support import import_module
+import_module('tkinter') # discard return
+itdir = import_module('idlelib.idle_test')
+
+# Without test_main present, regrtest.runtest_inner (line1219)
+# imitates unittest.main by calling
+# unittest.TestLoader().loadTestsFromModule(this_module)
+# which look for load_tests and uses it if found.
+load_tests = itdir.load_tests
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(verbosity=2, exit=False)
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -584,6 +584,7 @@
Bill Janssen
Thomas Jarosch
Juhana Jauhiainen
+Rajagopalasarma Jayakrishnan
Zbigniew Jędrzejewski-Szmek
Julien Jehannet
Drew Jenkins
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -13,6 +13,9 @@
- Issue #17206: Py_CLEAR(), Py_DECREF(), Py_XINCREF() and Py_XDECREF() now
expand their arguments once instead of multiple times. Patch written by Illia
Polosukhin.
+- Issue #15392: Create a unittest framework for IDLE.
+ Rajagopalasarma Jayakrishnan
+

- Issue #17937: Try harder to collect cyclic garbage at shutdown.


--
Repository URL: http://hg.python.org/cpython


python-checkins at python

May 27, 2013, 8:28 PM

Post #7 of 34 (167 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/138ddf15b220
changeset: 83944:138ddf15b220
parent: 83942:c5d4c041ab47
parent: 83943:29a2557d693e
user: Jason R. Coombs <jaraco [at] jaraco>
date: Mon May 27 23:26:36 2013 -0400
summary:
Merge with 3.3

files:
Doc/library/os.rst | 8 +-
Lib/test/test_os.py | 44 ++++++++-
Modules/posixmodule.c | 129 +++++++++++++++++++++++++++++-
3 files changed, 168 insertions(+), 13 deletions(-)


diff --git a/Doc/library/os.rst b/Doc/library/os.rst
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -2024,9 +2024,10 @@
Create a symbolic link pointing to *source* named *link_name*.

On Windows, a symlink represents either a file or a directory, and does not
- morph to the target dynamically. If *target_is_directory* is set to ``True``,
- the symlink will be created as a directory symlink, otherwise as a file symlink
- (the default). On non-Window platforms, *target_is_directory* is ignored.
+ morph to the target dynamically. If the target is present, the type of the
+ symlink will be created to match. Otherwise, the symlink will be created
+ as a directory if *target_is_directory* is ``True`` or a file symlink (the
+ default) otherwise. On non-Window platforms, *target_is_directory* is ignored.

Symbolic link support was introduced in Windows 6.0 (Vista). :func:`symlink`
will raise a :exc:`NotImplementedError` on Windows versions earlier than 6.0.
@@ -2042,6 +2043,7 @@
to the administrator level. Either obtaining the privilege or running your
application as an administrator are ways to successfully create symlinks.

+
:exc:`OSError` is raised when the function is called by an unprivileged
user.

diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -686,13 +686,8 @@
f.write("I'm " + path + " and proud of it. Blame test_os.\n")
f.close()
if support.can_symlink():
- if os.name == 'nt':
- def symlink_to_dir(src, dest):
- os.symlink(src, dest, True)
- else:
- symlink_to_dir = os.symlink
- symlink_to_dir(os.path.abspath(t2_path), link_path)
- symlink_to_dir('broken', broken_link_path)
+ os.symlink(os.path.abspath(t2_path), link_path)
+ symlink_to_dir('broken', broken_link_path, True)
sub2_tree = (sub2_path, ["link"], ["broken_link", "tmp3"])
else:
sub2_tree = (sub2_path, [], ["tmp3"])
@@ -1516,7 +1511,7 @@
os.remove(self.missing_link)

def test_directory_link(self):
- os.symlink(self.dirlink_target, self.dirlink, True)
+ os.symlink(self.dirlink_target, self.dirlink)
self.assertTrue(os.path.exists(self.dirlink))
self.assertTrue(os.path.isdir(self.dirlink))
self.assertTrue(os.path.islink(self.dirlink))
@@ -1610,6 +1605,38 @@
shutil.rmtree(level1)


+@support.skip_unless_symlink
+class NonLocalSymlinkTests(unittest.TestCase):
+
+ def setUp(self):
+ """
+ Create this structure:
+
+ base
+ \___ some_dir
+ """
+ os.makedirs('base/some_dir')
+
+ def tearDown(self):
+ shutil.rmtree('base')
+
+ def test_directory_link_nonlocal(self):
+ """
+ The symlink target should resolve relative to the link, not relative
+ to the current directory.
+
+ Then, link base/some_link -> base/some_dir and ensure that some_link
+ is resolved as a directory.
+
+ In issue13772, it was discovered that directory detection failed if
+ the symlink target was not specified relative to the current
+ directory, which was a defect in the implementation.
+ """
+ src = os.path.join('base', 'some_link')
+ os.symlink('some_dir', src)
+ assert os.path.isdir(src)
+
+
class FSEncodingTests(unittest.TestCase):
def test_nop(self):
self.assertEqual(os.fsencode(b'abc\xff'), b'abc\xff')
@@ -2243,6 +2270,7 @@
Pep383Tests,
Win32KillTests,
Win32SymlinkTests,
+ NonLocalSymlinkTests,
FSEncodingTests,
DeviceEncodingTests,
PidTests,
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -6735,6 +6735,124 @@
return (Py_CreateSymbolicLinkW && Py_CreateSymbolicLinkA);
}

+void _dirnameW(WCHAR *path) {
+ /* Remove the last portion of the path */
+
+ WCHAR *ptr;
+
+ /* walk the path from the end until a backslash is encountered */
+ for(ptr = path + wcslen(path); ptr != path; ptr--)
+ {
+ if(*ptr == *L"\\" || *ptr == *L"/") {
+ break;
+ }
+ }
+ *ptr = 0;
+}
+
+void _dirnameA(char *path) {
+ /* Remove the last portion of the path */
+
+ char *ptr;
+
+ /* walk the path from the end until a backslash is encountered */
+ for(ptr = path + strlen(path); ptr != path; ptr--)
+ {
+ if(*ptr == '\\' || *ptr == '/') {
+ break;
+ }
+ }
+ *ptr = 0;
+}
+
+int _is_absW(WCHAR *path) {
+ /* Is this path absolute? */
+
+ return path[0] == L'\\' || path[0] == L'/' || path[1] == L':';
+
+}
+
+int _is_absA(char *path) {
+ /* Is this path absolute? */
+
+ return path[0] == '\\' || path[0] == '/' || path[1] == ':';
+
+}
+
+void _joinW(WCHAR *dest_path, const WCHAR *root, const WCHAR *rest) {
+ /* join root and rest with a backslash */
+ int root_len;
+
+ if(_is_absW(rest)) {
+ wcscpy(dest_path, rest);
+ return;
+ }
+
+ root_len = wcslen(root);
+
+ wcscpy(dest_path, root);
+ if(root_len) {
+ dest_path[root_len] = *L"\\";
+ root_len += 1;
+ }
+ wcscpy(dest_path+root_len, rest);
+}
+
+void _joinA(char *dest_path, const char *root, const char *rest) {
+ /* join root and rest with a backslash */
+ int root_len;
+
+ if(_is_absA(rest)) {
+ strcpy(dest_path, rest);
+ return;
+ }
+
+ root_len = strlen(root);
+
+ strcpy(dest_path, root);
+ if(root_len) {
+ dest_path[root_len] = '\\';
+ root_len += 1;
+ }
+ strcpy(dest_path+root_len, rest);
+}
+
+int _check_dirW(WCHAR *src, WCHAR *dest)
+{
+ /* Return True if the path at src relative to dest is a directory */
+ WIN32_FILE_ATTRIBUTE_DATA src_info;
+ WCHAR dest_parent[MAX_PATH];
+ WCHAR src_resolved[MAX_PATH] = L"";
+
+ /* dest_parent = os.path.dirname(dest) */
+ wcscpy(dest_parent, dest);
+ _dirnameW(dest_parent);
+ /* src_resolved = os.path.join(dest_parent, src) */
+ _joinW(src_resolved, dest_parent, src);
+ return (
+ GetFileAttributesExW(src_resolved, GetFileExInfoStandard, &src_info)
+ && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
+ );
+}
+
+int _check_dirA(char *src, char *dest)
+{
+ /* Return True if the path at src relative to dest is a directory */
+ WIN32_FILE_ATTRIBUTE_DATA src_info;
+ char dest_parent[MAX_PATH];
+ char src_resolved[MAX_PATH] = "";
+
+ /* dest_parent = os.path.dirname(dest) */
+ strcpy(dest_parent, dest);
+ _dirnameW(dest_parent);
+ /* src_resolved = os.path.join(dest_parent, src) */
+ _joinW(src_resolved, dest_parent, src);
+ return (
+ GetFileAttributesExA(src_resolved, GetFileExInfoStandard, &src_info)
+ && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
+ );
+}
+
#endif

static PyObject *
@@ -6793,13 +6911,20 @@
}

#ifdef MS_WINDOWS
+
Py_BEGIN_ALLOW_THREADS
- if (dst.wide)
+ if (dst.wide) {
+ /* if src is a directory, ensure target_is_directory==1 */
+ target_is_directory |= _check_dirW(src.wide, dst.wide);
result = Py_CreateSymbolicLinkW(dst.wide, src.wide,
target_is_directory);
- else
+ }
+ else {
+ /* if src is a directory, ensure target_is_directory==1 */
+ target_is_directory |= _check_dirA(src.narrow, dst.narrow);
result = Py_CreateSymbolicLinkA(dst.narrow, src.narrow,
target_is_directory);
+ }
Py_END_ALLOW_THREADS

if (!result) {

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

May 27, 2013, 8:53 PM

Post #8 of 34 (167 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/eb1025b107c5
changeset: 83946:eb1025b107c5
parent: 83944:138ddf15b220
parent: 83945:8cebe8d537a4
user: Jason R. Coombs <jaraco [at] jaraco>
date: Mon May 27 23:53:02 2013 -0400
summary:
Merge with 3.3

files:
Lib/test/test_os.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)


diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -687,7 +687,7 @@
f.close()
if support.can_symlink():
os.symlink(os.path.abspath(t2_path), link_path)
- symlink_to_dir('broken', broken_link_path, True)
+ os.symlink('broken', broken_link_path, True)
sub2_tree = (sub2_path, ["link"], ["broken_link", "tmp3"])
else:
sub2_tree = (sub2_path, [], ["tmp3"])

--
Repository URL: http://hg.python.org/cpython


benjamin at python

May 27, 2013, 11:14 PM

Post #9 of 34 (167 views)
Permalink
Re: cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

2013/5/27 terry.reedy <python-checkins [at] python>:
> http://hg.python.org/cpython/rev/c5d4c041ab47
> changeset: 83942:c5d4c041ab47
> parent: 83940:2ea849fde22b
> parent: 83941:24c3e7e08168
> user: Terry Jan Reedy <tjreedy [at] udel>
> date: Mon May 27 21:33:40 2013 -0400
> summary:
> Merge with 3.3
>
> files:
> Lib/idlelib/CallTips.py | 4 +-
> Lib/idlelib/PathBrowser.py | 3 +-
> Lib/idlelib/idle_test/@README.txt | 63 +++++++++++

Is @README really the intended name of this file? Would README-TEST or
something similar be better?



--
Regards,
Benjamin
_______________________________________________
Python-checkins mailing list
Python-checkins [at] python
http://mail.python.org/mailman/listinfo/python-checkins


python-checkins at python

May 28, 2013, 7:22 PM

Post #10 of 34 (165 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/7a6a8a003553
changeset: 83970:7a6a8a003553
parent: 83968:672614d809a1
parent: 83969:968f6094788b
user: Terry Jan Reedy <tjreedy [at] udel>
date: Tue May 28 22:22:14 2013 -0400
summary:
Merge with 3.3

files:
Lib/idlelib/idle_test/@README.txt | 0
Lib/test/test_idle.py | 16 ++++++++--------
2 files changed, 8 insertions(+), 8 deletions(-)


diff --git a/Lib/idlelib/idle_test/@README.txt b/Lib/idlelib/idle_test/README.txt
rename from Lib/idlelib/idle_test/@README.txt
rename to Lib/idlelib/idle_test/README.txt
diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py
--- a/Lib/test/test_idle.py
+++ b/Lib/test/test_idle.py
@@ -1,13 +1,13 @@
-# Skip test if tkinter wasn't built or idlelib was deleted.
+# Skip test if _tkinter or _thread wasn't built or idlelib was deleted.
from test.support import import_module
-import_module('tkinter') # discard return
-itdir = import_module('idlelib.idle_test')
+import_module('tkinter')
+import_module('threading') # imported by PyShell, imports _thread
+idletest = import_module('idlelib.idle_test')

-# Without test_main present, regrtest.runtest_inner (line1219)
-# imitates unittest.main by calling
-# unittest.TestLoader().loadTestsFromModule(this_module)
-# which look for load_tests and uses it if found.
-load_tests = itdir.load_tests
+# Without test_main present, regrtest.runtest_inner (line1219) calls
+# unittest.TestLoader().loadTestsFromModule(this_module) which calls
+# load_tests() if it finds it. (Unittest.main does the same.)
+load_tests = idletest.load_tests

if __name__ == '__main__':
import unittest

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jun 5, 2013, 11:41 AM

Post #11 of 34 (158 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/367377d800a5
changeset: 84041:367377d800a5
parent: 84039:dfcb64f51f7b
parent: 84040:db4ecaf852e3
user: Terry Jan Reedy <tjreedy [at] udel>
date: Wed Jun 05 14:23:53 2013 -0400
summary:
Merge with 3.3

files:
Lib/idlelib/configSectionNameDialog.py | 111 +++++----
Lib/idlelib/idle_test/mock_tk.py | 63 +++++
Lib/idlelib/idle_test/test_config_name.py | 75 ++++++
3 files changed, 198 insertions(+), 51 deletions(-)


diff --git a/Lib/idlelib/configSectionNameDialog.py b/Lib/idlelib/configSectionNameDialog.py
--- a/Lib/idlelib/configSectionNameDialog.py
+++ b/Lib/idlelib/configSectionNameDialog.py
@@ -1,97 +1,106 @@
"""
Dialog that allows user to specify a new config file section name.
Used to get new highlight theme and keybinding set names.
+The 'return value' for the dialog, used two placed in configDialog.py,
+is the .result attribute set in the Ok and Cancel methods.
"""
from tkinter import *
import tkinter.messagebox as tkMessageBox

class GetCfgSectionNameDialog(Toplevel):
- def __init__(self,parent,title,message,usedNames):
+ def __init__(self, parent, title, message, used_names):
"""
message - string, informational message to display
- usedNames - list, list of names already in use for validity check
+ used_names - string collection, names already in use for validity check
"""
Toplevel.__init__(self, parent)
self.configure(borderwidth=5)
- self.resizable(height=FALSE,width=FALSE)
+ self.resizable(height=FALSE, width=FALSE)
self.title(title)
self.transient(parent)
self.grab_set()
self.protocol("WM_DELETE_WINDOW", self.Cancel)
self.parent = parent
- self.message=message
- self.usedNames=usedNames
- self.result=''
- self.CreateWidgets()
- self.withdraw() #hide while setting geometry
+ self.message = message
+ self.used_names = used_names
+ self.create_widgets()
+ self.withdraw() #hide while setting geometry
self.update_idletasks()
#needs to be done here so that the winfo_reqwidth is valid
self.messageInfo.config(width=self.frameMain.winfo_reqwidth())
- self.geometry("+%d+%d" %
- ((parent.winfo_rootx()+((parent.winfo_width()/2)
- -(self.winfo_reqwidth()/2)),
- parent.winfo_rooty()+((parent.winfo_height()/2)
- -(self.winfo_reqheight()/2)) )) ) #centre dialog over parent
- self.deiconify() #geometry set, unhide
+ self.geometry(
+ "+%d+%d" % (
+ parent.winfo_rootx() +
+ (parent.winfo_width()/2 - self.winfo_reqwidth()/2),
+ parent.winfo_rooty() +
+ (parent.winfo_height()/2 - self.winfo_reqheight()/2)
+ ) ) #centre dialog over parent
+ self.deiconify() #geometry set, unhide
self.wait_window()

- def CreateWidgets(self):
- self.name=StringVar(self)
- self.fontSize=StringVar(self)
- self.frameMain = Frame(self,borderwidth=2,relief=SUNKEN)
- self.frameMain.pack(side=TOP,expand=TRUE,fill=BOTH)
- self.messageInfo=Message(self.frameMain,anchor=W,justify=LEFT,padx=5,pady=5,
- text=self.message)#,aspect=200)
- entryName=Entry(self.frameMain,textvariable=self.name,width=30)
+ def create_widgets(self):
+ self.name = StringVar(self.parent)
+ self.fontSize = StringVar(self.parent)
+ self.frameMain = Frame(self, borderwidth=2, relief=SUNKEN)
+ self.frameMain.pack(side=TOP, expand=TRUE, fill=BOTH)
+ self.messageInfo = Message(self.frameMain, anchor=W, justify=LEFT,
+ padx=5, pady=5, text=self.message) #,aspect=200)
+ entryName = Entry(self.frameMain, textvariable=self.name, width=30)
entryName.focus_set()
- self.messageInfo.pack(padx=5,pady=5)#,expand=TRUE,fill=BOTH)
- entryName.pack(padx=5,pady=5)
- frameButtons=Frame(self)
- frameButtons.pack(side=BOTTOM,fill=X)
- self.buttonOk = Button(frameButtons,text='Ok',
- width=8,command=self.Ok)
- self.buttonOk.grid(row=0,column=0,padx=5,pady=5)
- self.buttonCancel = Button(frameButtons,text='Cancel',
- width=8,command=self.Cancel)
- self.buttonCancel.grid(row=0,column=1,padx=5,pady=5)
+ self.messageInfo.pack(padx=5, pady=5) #, expand=TRUE, fill=BOTH)
+ entryName.pack(padx=5, pady=5)

- def NameOk(self):
- #simple validity check for a sensible
- #ConfigParser file section name
- nameOk=1
- name=self.name.get()
- name.strip()
+ frameButtons = Frame(self, pady=2)
+ frameButtons.pack(side=BOTTOM)
+ self.buttonOk = Button(frameButtons, text='Ok',
+ width=8, command=self.Ok)
+ self.buttonOk.pack(side=LEFT, padx=5)
+ self.buttonCancel = Button(frameButtons, text='Cancel',
+ width=8, command=self.Cancel)
+ self.buttonCancel.pack(side=RIGHT, padx=5)
+
+ def name_ok(self):
+ ''' After stripping entered name, check that it is a sensible
+ ConfigParser file section name. Return it if it is, '' if not.
+ '''
+ name = self.name.get().strip()
if not name: #no name specified
tkMessageBox.showerror(title='Name Error',
message='No name specified.', parent=self)
- nameOk=0
elif len(name)>30: #name too long
tkMessageBox.showerror(title='Name Error',
message='Name too long. It should be no more than '+
'30 characters.', parent=self)
- nameOk=0
- elif name in self.usedNames:
+ name = ''
+ elif name in self.used_names:
tkMessageBox.showerror(title='Name Error',
message='This name is already in use.', parent=self)
- nameOk=0
- return nameOk
+ name = ''
+ return name

def Ok(self, event=None):
- if self.NameOk():
- self.result=self.name.get().strip()
+ name = self.name_ok()
+ if name:
+ self.result = name
self.destroy()

def Cancel(self, event=None):
- self.result=''
+ self.result = ''
self.destroy()

if __name__ == '__main__':
- #test the dialog
- root=Tk()
+ import unittest
+ unittest.main('idlelib.idle_test.test_config_name', verbosity=2, exit=False)
+
+ # also human test the dialog
+ root = Tk()
def run():
- keySeq=''
dlg=GetCfgSectionNameDialog(root,'Get Name',
- 'The information here should need to be word wrapped. Test.')
+ "After the text entered with [Ok] is stripped, <nothing>, "
+ "'abc', or more that 30 chars are errors. "
+ "Close with a valid entry (printed), [Cancel], or [X]",
+ {'abc'})
print(dlg.result)
- Button(root,text='Dialog',command=run).pack()
+ Message(root, text='').pack() # will be needed for oher dialog tests
+ Button(root, text='Click to begin dialog test', command=run).pack()
root.mainloop()
diff --git a/Lib/idlelib/idle_test/mock_tk.py b/Lib/idlelib/idle_test/mock_tk.py
new file mode 100644
--- /dev/null
+++ b/Lib/idlelib/idle_test/mock_tk.py
@@ -0,0 +1,63 @@
+"""Classes that replace tkinter gui objects used by an object being tested.
+A gui object is anything with a master or parent paramenter, which is typically
+required in spite of what the doc strings say.
+"""
+
+class Var:
+ "Use for String/Int/BooleanVar: incomplete"
+ def __init__(self, master=None, value=None, name=None):
+ self.master = master
+ self.value = value
+ self.name = name
+ def set(self, value):
+ self.value = value
+ def get(self):
+ return self.value
+
+class Mbox_func:
+ """Generic mock for messagebox functions. All have same call signature.
+ Mbox instantiates once for each function. Tester uses attributes.
+ """
+ def __init__(self):
+ self.result = None # The return for all show funcs
+ def __call__(self, title, message, *args, **kwds):
+ # Save all args for possible examination by tester
+ self.title = title
+ self.message = message
+ self.args = args
+ self.kwds = kwds
+ return self.result # Set by tester for ask functions
+
+class Mbox:
+ """Mock for tkinter.messagebox with an Mbox_func for each function.
+ This module was 'tkMessageBox' in 2.x; hence the 'import as' in 3.x.
+ Example usage in test_module.py for testing functios in module.py:
+ ---
+from idlelib.idle_test.mock_tk import Mbox
+import module
+
+orig_mbox = module.tkMessageBox
+showerror = Mbox.showerror # example, for attribute access in test methods
+
+class Test(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ module.tkMessageBox = Mbox
+
+ @classmethod
+ def tearDownClass(cls):
+ module.tkMessageBox = orig_mbox
+ ---
+ When tkMessageBox functions are the only gui making calls in a method,
+ this replacement makes the method gui-free and unit-testable.
+ For 'ask' functions, set func.result return before calling method.
+ """
+ askokcancel = Mbox_func() # True or False
+ askquestion = Mbox_func() # 'yes' or 'no'
+ askretrycancel = Mbox_func() # True or False
+ askyesno = Mbox_func() # True or False
+ askyesnocancel = Mbox_func() # True, False, or None
+ showerror = Mbox_func() # None
+ showinfo = Mbox_func() # None
+ showwarning = Mbox_func() # None
diff --git a/Lib/idlelib/idle_test/test_config_name.py b/Lib/idlelib/idle_test/test_config_name.py
new file mode 100644
--- /dev/null
+++ b/Lib/idlelib/idle_test/test_config_name.py
@@ -0,0 +1,75 @@
+"""Unit tests for idlelib.configSectionNameDialog"""
+import unittest
+from idlelib.idle_test.mock_tk import Var, Mbox
+from idlelib import configSectionNameDialog as name_dialog_module
+
+name_dialog = name_dialog_module.GetCfgSectionNameDialog
+
+class Dummy_name_dialog:
+ # Mock for testing the following methods of name_dialog
+ name_ok = name_dialog.name_ok
+ Ok = name_dialog.Ok
+ Cancel = name_dialog.Cancel
+ # Attributes, constant or variable, needed for tests
+ used_names = ['used']
+ name = Var()
+ result = None
+ destroyed = False
+ def destroy(self):
+ self.destroyed = True
+
+# name_ok calls Mbox.showerror if name is not ok
+orig_mbox = name_dialog_module.tkMessageBox
+showerror = Mbox.showerror
+
+class TestConfigName(unittest.TestCase):
+ dialog = Dummy_name_dialog()
+
+ @classmethod
+ def setUpClass(cls):
+ name_dialog_module.tkMessageBox = Mbox
+
+ @classmethod
+ def tearDownClass(cls):
+ name_dialog_module.tkMessageBox = orig_mbox
+
+ def test_blank_name(self):
+ self.dialog.name.set(' ')
+ self.assertEqual(self.dialog.name_ok(), '')
+ self.assertEqual(showerror.title, 'Name Error')
+ self.assertIn('No', showerror.message)
+
+ def test_used_name(self):
+ self.dialog.name.set('used')
+ self.assertEqual(self.dialog.name_ok(), '')
+ self.assertEqual(showerror.title, 'Name Error')
+ self.assertIn('use', showerror.message)
+
+ def test_long_name(self):
+ self.dialog.name.set('good'*8)
+ self.assertEqual(self.dialog.name_ok(), '')
+ self.assertEqual(showerror.title, 'Name Error')
+ self.assertIn('too long', showerror.message)
+
+ def test_good_name(self):
+ self.dialog.name.set(' good ')
+ showerror.title = 'No Error' # should not be called
+ self.assertEqual(self.dialog.name_ok(), 'good')
+ self.assertEqual(showerror.title, 'No Error')
+
+ def test_ok(self):
+ self.dialog.destroyed = False
+ self.dialog.name.set('good')
+ self.dialog.Ok()
+ self.assertEqual(self.dialog.result, 'good')
+ self.assertTrue(self.dialog.destroyed)
+
+ def test_cancel(self):
+ self.dialog.destroyed = False
+ self.dialog.Cancel()
+ self.assertEqual(self.dialog.result, '')
+ self.assertTrue(self.dialog.destroyed)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2, exit=False)

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jun 5, 2013, 11:41 AM

Post #12 of 34 (158 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/9c06a9a8bba1
changeset: 84044:9c06a9a8bba1
parent: 84041:367377d800a5
parent: 84043:382f4718e765
user: Terry Jan Reedy <tjreedy [at] udel>
date: Wed Jun 05 14:36:50 2013 -0400
summary:
Merge with 3.3

files:
Lib/idlelib/configSectionNameDialog.py | 2 +-
Lib/idlelib/idle_test/test_config_name.py | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)


diff --git a/Lib/idlelib/configSectionNameDialog.py b/Lib/idlelib/configSectionNameDialog.py
--- a/Lib/idlelib/configSectionNameDialog.py
+++ b/Lib/idlelib/configSectionNameDialog.py
@@ -91,7 +91,7 @@
if __name__ == '__main__':
import unittest
unittest.main('idlelib.idle_test.test_config_name', verbosity=2, exit=False)
-
+
# also human test the dialog
root = Tk()
def run():
diff --git a/Lib/idlelib/idle_test/test_config_name.py b/Lib/idlelib/idle_test/test_config_name.py
--- a/Lib/idlelib/idle_test/test_config_name.py
+++ b/Lib/idlelib/idle_test/test_config_name.py
@@ -24,7 +24,7 @@

class TestConfigName(unittest.TestCase):
dialog = Dummy_name_dialog()
-
+
@classmethod
def setUpClass(cls):
name_dialog_module.tkMessageBox = Mbox
@@ -38,13 +38,13 @@
self.assertEqual(self.dialog.name_ok(), '')
self.assertEqual(showerror.title, 'Name Error')
self.assertIn('No', showerror.message)
-
+
def test_used_name(self):
self.dialog.name.set('used')
self.assertEqual(self.dialog.name_ok(), '')
self.assertEqual(showerror.title, 'Name Error')
self.assertIn('use', showerror.message)
-
+
def test_long_name(self):
self.dialog.name.set('good'*8)
self.assertEqual(self.dialog.name_ok(), '')
@@ -56,7 +56,7 @@
showerror.title = 'No Error' # should not be called
self.assertEqual(self.dialog.name_ok(), 'good')
self.assertEqual(showerror.title, 'No Error')
-
+
def test_ok(self):
self.dialog.destroyed = False
self.dialog.name.set('good')
@@ -69,7 +69,7 @@
self.dialog.Cancel()
self.assertEqual(self.dialog.result, '')
self.assertTrue(self.dialog.destroyed)
-
+

if __name__ == '__main__':
unittest.main(verbosity=2, exit=False)

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jun 15, 2013, 12:11 PM

Post #13 of 34 (139 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/fcb686e720ff
changeset: 84153:fcb686e720ff
parent: 84150:1e141c2cc0d7
parent: 84152:3d75bd69e5a9
user: Andrew Kuchling <amk [at] amk>
date: Sat Jun 15 15:10:08 2013 -0400
summary:
Merge with 3.3

files:
Lib/test/test_curses.py | 13 +++++++++++++
Misc/NEWS | 3 +++
Modules/_curses_panel.c | 4 ++++
3 files changed, 20 insertions(+), 0 deletions(-)


diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py
--- a/Lib/test/test_curses.py
+++ b/Lib/test/test_curses.py
@@ -252,6 +252,18 @@
except curses.panel.error:
pass

+def test_userptr_memory_leak(stdscr):
+ w = curses.newwin(10, 10)
+ p = curses.panel.new_panel(w)
+ obj = object()
+ nrefs = sys.getrefcount(obj)
+ for i in range(100):
+ p.set_userptr(obj)
+
+ p.set_userptr(None)
+ if sys.getrefcount(obj) != nrefs:
+ raise RuntimeError("set_userptr leaked references")
+
def test_resize_term(stdscr):
if hasattr(curses, 'resizeterm'):
lines, cols = curses.LINES, curses.COLS
@@ -317,6 +329,7 @@
module_funcs(stdscr)
window_funcs(stdscr)
test_userptr_without_set(stdscr)
+ test_userptr_memory_leak(stdscr)
test_resize_term(stdscr)
test_issue6243(stdscr)
test_unget_wch(stdscr)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -383,6 +383,9 @@
the default for linking if LDSHARED is not also overriden. This restores
Distutils behavior introduced in 3.2.3 and inadvertently dropped in 3.3.0.

+- Issue #18113: Fixed a refcount leak in the curses.panel module's
+ set_userptr() method. Reported by Atsuo Ishimoto.
+
- Implement PEP 443 "Single-dispatch generic functions".

- Implement PEP 435 "Adding an Enum type to the Python standard library".
diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c
--- a/Modules/_curses_panel.c
+++ b/Modules/_curses_panel.c
@@ -322,6 +322,10 @@
static PyObject *
PyCursesPanel_set_panel_userptr(PyCursesPanelObject *self, PyObject *obj)
{
+ PyObject *oldobj;
+ PyCursesInitialised;
+ oldobj = (PyObject *) panel_userptr(self->pan);
+ Py_XDECREF(oldobj);
Py_INCREF(obj);
return PyCursesCheckERR(set_panel_userptr(self->pan, (void*)obj),
"set_panel_userptr");

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jun 16, 2013, 10:04 AM

Post #14 of 34 (138 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/81648329b37a
changeset: 84166:81648329b37a
parent: 84164:4f7c25ab2ed2
parent: 84165:55f611f55952
user: Andrew Kuchling <amk [at] amk>
date: Sun Jun 16 13:02:55 2013 -0400
summary:
Merge with 3.3

files:
Doc/library/codecs.rst | 6 +++-
Doc/library/functions.rst | 40 ++++++++++++++++++++------
Lib/codecs.py | 1 +
Modules/_io/_iomodule.c | 4 +-
Modules/_io/textio.c | 5 ++-
5 files changed, 41 insertions(+), 15 deletions(-)


diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst
--- a/Doc/library/codecs.rst
+++ b/Doc/library/codecs.rst
@@ -78,7 +78,11 @@
reference (for encoding only)
* ``'backslashreplace'``: replace with backslashed escape sequences (for
encoding only)
- * ``'surrogateescape'``: replace with surrogate U+DCxx, see :pep:`383`
+ * ``'surrogateescape'``: on decoding, replace with code points in the Unicode
+ Private Use Area ranging from U+DC80 to U+DCFF. These private code
+ points will then be turned back into the same bytes when the
+ ``surrogateescape`` error handler is used when encoding the data.
+ (See :pep:`383` for more.)

as well as any other error handling name defined via :func:`register_error`.

diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -905,16 +905,36 @@
the list of supported encodings.

*errors* is an optional string that specifies how encoding and decoding
- errors are to be handled--this cannot be used in binary mode. Pass
- ``'strict'`` to raise a :exc:`ValueError` exception if there is an encoding
- error (the default of ``None`` has the same effect), or pass ``'ignore'`` to
- ignore errors. (Note that ignoring encoding errors can lead to data loss.)
- ``'replace'`` causes a replacement marker (such as ``'?'``) to be inserted
- where there is malformed data. When writing, ``'xmlcharrefreplace'``
- (replace with the appropriate XML character reference) or
- ``'backslashreplace'`` (replace with backslashed escape sequences) can be
- used. Any other error handling name that has been registered with
- :func:`codecs.register_error` is also valid.
+ errors are to be handled--this cannot be used in binary mode.
+ A variety of standard error handlers are available, though any
+ error handling name that has been registered with
+ :func:`codecs.register_error` is also valid. The standard names
+ are:
+
+ * ``'strict'`` to raise a :exc:`ValueError` exception if there is
+ an encoding error. The default value of ``None`` has the same
+ effect.
+
+ * ``'ignore'`` ignores errors. Note that ignoring encoding errors
+ can lead to data loss.
+
+ * ``'replace'`` causes a replacement marker (such as ``'?'``) to be inserted
+ where there is malformed data.
+
+ * ``'surrogateescape'`` will represent any incorrect bytes as code
+ points in the Unicode Private Use Area ranging from U+DC80 to
+ U+DCFF. These private code points will then be turned back into
+ the same bytes when the ``surrogateescape`` error handler is used
+ when writing data. This is useful for processing files in an
+ unknown encoding.
+
+ * ``'xmlcharrefreplace'`` is only supported when writing to a file.
+ Characters not supported by the encoding are replaced with the
+ appropriate XML character reference ``&#nnn;``.
+
+ * ``'backslashreplace'`` (also only supported when writing)
+ replaces unsupported characters with Python's backslashed escape
+ sequences.

.. index::
single: universal newlines; open() built-in function
diff --git a/Lib/codecs.py b/Lib/codecs.py
--- a/Lib/codecs.py
+++ b/Lib/codecs.py
@@ -105,6 +105,7 @@
Python will use the official U+FFFD REPLACEMENT
CHARACTER for the builtin Unicode codecs on
decoding and '?' on encoding.
+ 'surrogateescape' - replace with private codepoints U+DCnn.
'xmlcharrefreplace' - Replace with the appropriate XML
character reference (only for encoding).
'backslashreplace' - Replace with backslashed escape sequences
diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c
--- a/Modules/_io/_iomodule.c
+++ b/Modules/_io/_iomodule.c
@@ -168,8 +168,8 @@
"'strict' to raise a ValueError exception if there is an encoding error\n"
"(the default of None has the same effect), or pass 'ignore' to ignore\n"
"errors. (Note that ignoring encoding errors can lead to data loss.)\n"
-"See the documentation for codecs.register for a list of the permitted\n"
-"encoding error strings.\n"
+"See the documentation for codecs.register or run 'help(codecs.Codec)'\n"
+"for a list of the permitted encoding error strings.\n"
"\n"
"newline controls how universal newlines works (it only applies to text\n"
"mode). It can be None, '', '\\n', '\\r', and '\\r\\n'. It works as\n"
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -642,8 +642,9 @@
"encoding gives the name of the encoding that the stream will be\n"
"decoded or encoded with. It defaults to locale.getpreferredencoding(False).\n"
"\n"
- "errors determines the strictness of encoding and decoding (see the\n"
- "codecs.register) and defaults to \"strict\".\n"
+ "errors determines the strictness of encoding and decoding (see\n"
+ "help(codecs.Codec) or the documentation for codecs.register) and\n"
+ "defaults to \"strict\".\n"
"\n"
"newline controls how line endings are handled. It can be None, '',\n"
"'\\n', '\\r', and '\\r\\n'. It works as follows:\n"

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jun 28, 2013, 4:00 PM

Post #15 of 34 (128 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/03747d64c042
changeset: 84363:03747d64c042
parent: 84360:446ae05de566
parent: 84362:0760b58526ba
user: Terry Jan Reedy <tjreedy [at] udel>
date: Fri Jun 28 18:59:52 2013 -0400
summary:
Merge with 3.3

files:
Lib/fileinput.py | 12 +++++-------
Misc/ACKS | 1 +
2 files changed, 6 insertions(+), 7 deletions(-)


diff --git a/Lib/fileinput.py b/Lib/fileinput.py
--- a/Lib/fileinput.py
+++ b/Lib/fileinput.py
@@ -90,13 +90,11 @@

def input(files=None, inplace=False, backup="", bufsize=0,
mode="r", openhook=None):
- """input(files=None, inplace=False, backup="", bufsize=0, \
-mode="r", openhook=None)
+ """Return an instance of the FileInput class, which can be iterated.

- Create an instance of the FileInput class. The instance will be used
- as global state for the functions of this module, and is also returned
- to use during iteration. The parameters to this function will be passed
- along to the constructor of the FileInput class.
+ The parameters are passed to the constructor of the FileInput class.
+ The returned instance, in addition to being an iterator,
+ keeps global state for the functions of this module,.
"""
global _state
if _state and _state._file:
@@ -183,7 +181,7 @@
return _state.isstdin()

class FileInput:
- """class FileInput([files[, inplace[, backup[, mode[, openhook]]]]])
+ """FileInput([files[, inplace[, backup[, bufsize, [, mode[, openhook]]]]]])

Class FileInput is the implementation of the module; its methods
filename(), lineno(), fileline(), isfirstline(), isstdin(), fileno(),
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1154,6 +1154,7 @@
Joel Shprentz
Itamar Shtull-Trauring
Yue Shuaijie
+Terrel Shumway
Eric Siegerman
Paul Sijben
SilentGhost

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jun 28, 2013, 8:53 PM

Post #16 of 34 (128 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/373d629bd5fc
changeset: 84368:373d629bd5fc
parent: 84365:2176c1867b34
parent: 84366:c15d0baac3d6
user: Terry Jan Reedy <tjreedy [at] udel>
date: Fri Jun 28 23:52:05 2013 -0400
summary:
Merge with 3.3

files:
Lib/idlelib/PyShell.py | 82 +++++++++-----
Lib/idlelib/idle_test/test_warning.py | 73 +++++++++++++
Lib/idlelib/run.py | 56 ++++++---
3 files changed, 162 insertions(+), 49 deletions(-)


diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py
--- a/Lib/idlelib/PyShell.py
+++ b/Lib/idlelib/PyShell.py
@@ -45,35 +45,55 @@
# internal warnings to the console. ScriptBinding.check_syntax() will
# temporarily redirect the stream to the shell window to display warnings when
# checking user's code.
-global warning_stream
-warning_stream = sys.__stderr__
-try:
- import warnings
-except ImportError:
- pass
-else:
- def idle_showwarning(message, category, filename, lineno,
- file=None, line=None):
- if file is None:
- file = warning_stream
- try:
- file.write(warnings.formatwarning(message, category, filename,
- lineno, line=line))
- except OSError:
- pass ## file (probably __stderr__) is invalid, warning dropped.
- warnings.showwarning = idle_showwarning
- def idle_formatwarning(message, category, filename, lineno, line=None):
- """Format warnings the IDLE way"""
- s = "\nWarning (from warnings module):\n"
- s += ' File \"%s\", line %s\n' % (filename, lineno)
- if line is None:
- line = linecache.getline(filename, lineno)
- line = line.strip()
- if line:
- s += " %s\n" % line
- s += "%s: %s\n>>> " % (category.__name__, message)
- return s
- warnings.formatwarning = idle_formatwarning
+warning_stream = sys.__stderr__ # None, at least on Windows, if no console.
+import warnings
+
+def idle_formatwarning(message, category, filename, lineno, line=None):
+ """Format warnings the IDLE way."""
+
+ s = "\nWarning (from warnings module):\n"
+ s += ' File \"%s\", line %s\n' % (filename, lineno)
+ if line is None:
+ line = linecache.getline(filename, lineno)
+ line = line.strip()
+ if line:
+ s += " %s\n" % line
+ s += "%s: %s\n" % (category.__name__, message)
+ return s
+
+def idle_showwarning(
+ message, category, filename, lineno, file=None, line=None):
+ """Show Idle-format warning (after replacing warnings.showwarning).
+
+ The differences are the formatter called, the file=None replacement,
+ which can be None, the capture of the consequence AttributeError,
+ and the output of a hard-coded prompt.
+ """
+ if file is None:
+ file = warning_stream
+ try:
+ file.write(idle_formatwarning(
+ message, category, filename, lineno, line=line))
+ file.write(">>> ")
+ except (AttributeError, OSError):
+ pass # if file (probably __stderr__) is invalid, skip warning.
+
+_warnings_showwarning = None
+
+def capture_warnings(capture):
+ "Replace warning.showwarning with idle_showwarning, or reverse."
+
+ global _warnings_showwarning
+ if capture:
+ if _warnings_showwarning is None:
+ _warnings_showwarning = warnings.showwarning
+ warnings.showwarning = idle_showwarning
+ else:
+ if _warnings_showwarning is not None:
+ warnings.showwarning = _warnings_showwarning
+ _warnings_showwarning = None
+
+capture_warnings(True)

def extended_linecache_checkcache(filename=None,
orig_checkcache=linecache.checkcache):
@@ -1425,6 +1445,7 @@
def main():
global flist, root, use_subprocess

+ capture_warnings(True)
use_subprocess = True
enable_shell = False
enable_edit = False
@@ -1559,7 +1580,10 @@
while flist.inversedict: # keep IDLE running while files are open.
root.mainloop()
root.destroy()
+ capture_warnings(False)

if __name__ == "__main__":
sys.modules['PyShell'] = sys.modules['__main__']
main()
+
+capture_warnings(False) # Make sure turned off; see issue 18081
diff --git a/Lib/idlelib/idle_test/test_warning.py b/Lib/idlelib/idle_test/test_warning.py
new file mode 100644
--- /dev/null
+++ b/Lib/idlelib/idle_test/test_warning.py
@@ -0,0 +1,73 @@
+'''Test warnings replacement in PyShell.py and run.py.
+
+This file could be expanded to include traceback overrides
+(in same two modules). If so, change name.
+Revise if output destination changes (http://bugs.python.org/issue18318).
+Make sure warnings module is left unaltered (http://bugs.python.org/issue18081).
+'''
+
+import unittest
+from test.support import captured_stderr
+
+import warnings
+# Try to capture default showwarning before Idle modules are imported.
+showwarning = warnings.showwarning
+# But if we run this file within idle, we are in the middle of the run.main loop
+# and default showwarnings has already been replaced.
+running_in_idle = 'idle' in showwarning.__name__
+
+from idlelib import run
+from idlelib import PyShell as shell
+
+# The following was generated from PyShell.idle_formatwarning
+# and checked as matching expectation.
+idlemsg = '''
+Warning (from warnings module):
+ File "test_warning.py", line 99
+ Line of code
+UserWarning: Test
+'''
+shellmsg = idlemsg + ">>> "
+
+class RunWarnTest(unittest.TestCase):
+
+ @unittest.skipIf(running_in_idle, "Does not work when run within Idle.")
+ def test_showwarnings(self):
+ self.assertIs(warnings.showwarning, showwarning)
+ run.capture_warnings(True)
+ self.assertIs(warnings.showwarning, run.idle_showwarning_subproc)
+ run.capture_warnings(False)
+ self.assertIs(warnings.showwarning, showwarning)
+
+ def test_run_show(self):
+ with captured_stderr() as f:
+ run.idle_showwarning_subproc(
+ 'Test', UserWarning, 'test_warning.py', 99, f, 'Line of code')
+ # The following uses .splitlines to erase line-ending differences
+ self.assertEqual(idlemsg.splitlines(), f.getvalue().splitlines())
+
+class ShellWarnTest(unittest.TestCase):
+
+ @unittest.skipIf(running_in_idle, "Does not work when run within Idle.")
+ def test_showwarnings(self):
+ self.assertIs(warnings.showwarning, showwarning)
+ shell.capture_warnings(True)
+ self.assertIs(warnings.showwarning, shell.idle_showwarning)
+ shell.capture_warnings(False)
+ self.assertIs(warnings.showwarning, showwarning)
+
+ def test_idle_formatter(self):
+ # Will fail if format changed without regenerating idlemsg
+ s = shell.idle_formatwarning(
+ 'Test', UserWarning, 'test_warning.py', 99, 'Line of code')
+ self.assertEqual(idlemsg, s)
+
+ def test_shell_show(self):
+ with captured_stderr() as f:
+ shell.idle_showwarning(
+ 'Test', UserWarning, 'test_warning.py', 99, f, 'Line of code')
+ self.assertEqual(shellmsg.splitlines(), f.getvalue().splitlines())
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2, exit=False)
diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py
--- a/Lib/idlelib/run.py
+++ b/Lib/idlelib/run.py
@@ -23,36 +23,46 @@

LOCALHOST = '127.0.0.1'

-try:
- import warnings
-except ImportError:
- pass
-else:
- def idle_formatwarning_subproc(message, category, filename, lineno,
- line=None):
- """Format warnings the IDLE way"""
- s = "\nWarning (from warnings module):\n"
- s += ' File \"%s\", line %s\n' % (filename, lineno)
- if line is None:
- line = linecache.getline(filename, lineno)
- line = line.strip()
- if line:
- s += " %s\n" % line
- s += "%s: %s\n" % (category.__name__, message)
- return s
- warnings.formatwarning = idle_formatwarning_subproc
+import warnings

+def idle_showwarning_subproc(
+ message, category, filename, lineno, file=None, line=None):
+ """Show Idle-format warning after replacing warnings.showwarning.

+ The only difference is the formatter called.
+ """
+ if file is None:
+ file = sys.stderr
+ try:
+ file.write(PyShell.idle_formatwarning(
+ message, category, filename, lineno, line))
+ except IOError:
+ pass # the file (probably stderr) is invalid - this warning gets lost.
+
+_warnings_showwarning = None
+
+def capture_warnings(capture):
+ "Replace warning.showwarning with idle_showwarning_subproc, or reverse."
+
+ global _warnings_showwarning
+ if capture:
+ if _warnings_showwarning is None:
+ _warnings_showwarning = warnings.showwarning
+ warnings.showwarning = idle_showwarning_subproc
+ else:
+ if _warnings_showwarning is not None:
+ warnings.showwarning = _warnings_showwarning
+ _warnings_showwarning = None
+
+capture_warnings(True)
tcl = tkinter.Tcl()

-
def handle_tk_events(tcl=tcl):
"""Process any tk events that are ready to be dispatched if tkinter
has been imported, a tcl interpreter has been created and tk has been
loaded."""
tcl.eval("update")

-
# Thread shared globals: Establish a queue between a subthread (which handles
# the socket) and the main thread (which runs user code), plus global
# completion, exit and interruptable (the main thread) flags:
@@ -91,6 +101,8 @@
print("IDLE Subprocess: no IP port passed in sys.argv.",
file=sys.__stderr__)
return
+
+ capture_warnings(True)
sys.argv[:] = [""]
sockthread = threading.Thread(target=manage_socket,
name='SockThread',
@@ -118,6 +130,7 @@
exit_now = True
continue
except SystemExit:
+ capture_warnings(False)
raise
except:
type, value, tb = sys.exc_info()
@@ -247,6 +260,7 @@
if no_exitfunc:
import atexit
atexit._clear()
+ capture_warnings(False)
sys.exit(0)

class MyRPCServer(rpc.RPCServer):
@@ -386,3 +400,5 @@
sys.last_value = val
item = StackViewer.StackTreeItem(flist, tb)
return RemoteObjectBrowser.remote_object_tree_item(item)
+
+capture_warnings(False) # Make sure turned off; see issue 18081

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jun 29, 2013, 10:16 AM

Post #17 of 34 (128 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/b8d95dfcafa3
changeset: 84373:b8d95dfcafa3
parent: 84370:f3f38c84aebc
parent: 84372:b3d19f0494e7
user: Terry Jan Reedy <tjreedy [at] udel>
date: Sat Jun 29 13:16:17 2013 -0400
summary:
Merge with 3.3

files:
Doc/library/unittest.rst | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)


diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst
--- a/Doc/library/unittest.rst
+++ b/Doc/library/unittest.rst
@@ -950,7 +950,7 @@
a regular expression object or a string containing a regular expression
suitable for use by :func:`re.search`. Examples::

- self.assertRaisesRegex(ValueError, 'invalid literal for.*XYZ$',
+ self.assertRaisesRegex(ValueError, "invalid literal for.*XYZ'$",
int, 'XYZ')

or::

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jun 29, 2013, 3:30 PM

Post #18 of 34 (127 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/171561855659
changeset: 84384:171561855659
parent: 84382:4c7426c3ceab
parent: 84383:c818c215f1a4
user: Terry Jan Reedy <tjreedy [at] udel>
date: Sat Jun 29 18:22:25 2013 -0400
summary:
Merge with 3.3

files:
Lib/idlelib/idle_test/README.txt | 93 +++++++++++++------
Lib/test/test_idle.py | 5 +
2 files changed, 70 insertions(+), 28 deletions(-)


diff --git a/Lib/idlelib/idle_test/README.txt b/Lib/idlelib/idle_test/README.txt
--- a/Lib/idlelib/idle_test/README.txt
+++ b/Lib/idlelib/idle_test/README.txt
@@ -1,14 +1,19 @@
README FOR IDLE TESTS IN IDLELIB.IDLE_TEST

+
+1. Test Files
+
The idle directory, idlelib, has over 60 xyz.py files. The idle_test
-subdirectory should contain a test_xyy.py for each one. (For test modules,
-make 'xyz' lower case.) Each should start with the following cut-paste
-template, with the blanks after after '.'. 'as', and '_' filled in.
+subdirectory should contain a test_xyy.py for each. (For test modules, make
+'xyz' lower case, and possibly shorten it.) Each file should start with the
+something like the following template, with the blanks after after '.' and 'as',
+and before and after '_' filled in.
---
import unittest
-import idlelib. as
+from test.support import requires
+import idlelib. as

-class Test_(unittest.TestCase):
+class _Test(unittest.TestCase):

def test_(self):

@@ -21,43 +26,75 @@
with xyz (lowercased) added after 'test_'.
---
if __name__ == "__main__":
+ from test import support; support.use_resources = ['gui']
import unittest
unittest.main('idlelib.idle_test.test_', verbosity=2, exit=False)
---

-In Idle, pressing F5 in an editor window with either xyz.py or test_xyz.py
-loaded will then run the test with the version of Python running Idle and
-tracebacks will appear in the Shell window. The options are appropriate for
-developers running (as opposed to importing) either type of file during
-development: verbosity=2 lists all test_y methods; exit=False avoids a
-spurious sys.exit traceback when running in Idle. The following command
-lines also run test_xyz.py
+
+2. Gui Tests
+
+Gui tests need 'requires' and 'use_resources' from test.support
+(test.test_support in 2.7). A test is a gui test if it creates a Tk root or
+master object either directly or indirectly by instantiating a tkinter or
+idle class. For the benefit of buildbot machines that do not have a graphics
+screen, gui tests must be 'guarded' by "requires('gui')" in a setUp
+function or method. This will typically be setUpClass.
+---
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+---
+All gui objects must be destroyed by the end of the test, perhaps in a tearDown
+function.
+
+Support.requires('gui') returns true if it is either called in a main module
+(which never happens on buildbots) or if use_resources contains 'gui'.
+Use_resources is set by test.regrtest but not by unittest. So when running
+tests in another module with unittest, we set it ourselves, as in the xyz.py
+template above.
+
+Since non-gui tests always run, but gui tests only sometimes, tests of non-gui
+operations should best avoid needing a gui. Methods that make incidental use of
+tkinter variables and messageboxes can do this by using the mock classes in
+idle_test/mock_tk.py.
+
+
+3. Running Tests
+
+Assume that xyz.py and test_xyz.py end with the "if __name__" statements given
+above. In Idle, pressing F5 in an editor window with either loaded will run all
+tests in the test_xyz file with the version of Python running Idle. The test
+report and any tracebacks will appear in the Shell window. The options in these
+"if __name__" statements are appropriate for developers running (as opposed to
+importing) either of the files during development: verbosity=2 lists all test
+methods in the file; exit=False avoids a spurious sys.exit traceback that would
+otherwise occur when running in Idle. The following command lines also run
+all test methods, including gui tests, in test_xyz.py. (The exceptions are that
+idlelib and idlelib.idle start Idle and idlelib.PyShell should (issue 18330).)

python -m idlelib.xyz # With the capitalization of the xyz module
-python -m unittest -v idlelib.idle_test.test_xyz
+python -m idlelib.idle_test.test_xyz

-To run all idle tests either interactively ('>>>', with unittest imported)
-or from a command line, use one of the following.
+To run all idle_test/test_*.py tests, either interactively
+('>>>', with unittest imported) or from a command line, use one of the
+following. (Notes: unittest does not run gui tests; in 2.7, 'test ' (with the
+space) is 'test.regrtest '; where present, -v and -ugui can be omitted.)

>>> unittest.main('idlelib.idle_test', verbosity=2, exit=False)
python -m unittest -v idlelib.idle_test
+python -m test -v -ugui test_idle
python -m test.test_idle
-python -m test test_idle

-The idle tests are 'discovered' in idlelib.idle_test.__init__.load_tests,
+The idle tests are 'discovered' by idlelib.idle_test.__init__.load_tests,
which is also imported into test.test_idle. Normally, neither file should be
-changed when working on individual test modules. The last command runs runs
+changed when working on individual test modules. The third command runs runs
unittest indirectly through regrtest. The same happens when the entire test
-suite is run with 'python -m test'. So it must work for buildbots to stay green.
+suite is run with 'python -m test'. So that command must work for buildbots
+to stay green. Idle tests must not disturb the environment in a way that
+makes other tests fail (issue 18081).

-To run an individual Testcase or test method, extend the
-dotted name given to unittest on the command line.
+To run an individual Testcase or test method, extend the dotted name given to
+unittest on the command line. (But gui tests will not this way.)

python -m unittest -v idlelib.idle_test.text_xyz.Test_case.test_meth
-
-To disable test/test_idle.py, there are at least two choices.
-a. Comment out 'load_tests' line, no no tests are discovered (simple and safe);
-Running no tests passes, so there is no indication that nothing was run.
-b.Before that line, make module an unexpected skip for regrtest with
-import unittest; raise unittest.SkipTest('skip for buildbots')
-When run directly with unittest, this causes a normal exit and traceback.
\ No newline at end of file
diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py
--- a/Lib/test/test_idle.py
+++ b/Lib/test/test_idle.py
@@ -10,5 +10,10 @@
load_tests = idletest.load_tests

if __name__ == '__main__':
+ # Until unittest supports resources, we emulate regrtest's -ugui
+ # so loaded tests run the same as if textually present here.
+ # If any Idle test ever needs another resource, add it to the list.
+ from test import support
+ support.use_resources = ['gui'] # use_resources is initially None
import unittest
unittest.main(verbosity=2, exit=False)

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jun 30, 2013, 1:53 PM

Post #19 of 34 (126 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/6584e1ddc347
changeset: 84394:6584e1ddc347
parent: 84390:29e7f6a2dc0d
parent: 84393:9d65716367c1
user: Terry Jan Reedy <tjreedy [at] udel>
date: Sun Jun 30 16:52:40 2013 -0400
summary:
Merge with 3.3

files:
Lib/idlelib/Delegator.py | 8 --------
1 files changed, 0 insertions(+), 8 deletions(-)


diff --git a/Lib/idlelib/Delegator.py b/Lib/idlelib/Delegator.py
--- a/Lib/idlelib/Delegator.py
+++ b/Lib/idlelib/Delegator.py
@@ -20,14 +20,6 @@
pass
self.__cache.clear()

- def cachereport(self):
- keys = list(self.__cache.keys())
- keys.sort()
- print(keys)
-
def setdelegate(self, delegate):
self.resetcache()
self.delegate = delegate
-
- def getdelegate(self):
- return self.delegate

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jun 30, 2013, 3:38 PM

Post #20 of 34 (126 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/dbdb6f7f9a1a
changeset: 84401:dbdb6f7f9a1a
parent: 84398:ae69436eb7c2
parent: 84400:c7605471e8ae
user: Terry Jan Reedy <tjreedy [at] udel>
date: Sun Jun 30 18:37:51 2013 -0400
summary:
Merge with 3.3

files:
Lib/idlelib/Delegator.py | 4 +-
Lib/idlelib/idle_test/test_delegator.py | 37 +++++++++++++
2 files changed, 39 insertions(+), 2 deletions(-)


diff --git a/Lib/idlelib/Delegator.py b/Lib/idlelib/Delegator.py
--- a/Lib/idlelib/Delegator.py
+++ b/Lib/idlelib/Delegator.py
@@ -4,12 +4,12 @@

def __init__(self, delegate=None):
self.delegate = delegate
- self.__cache = {}
+ self.__cache = set()

def __getattr__(self, name):
attr = getattr(self.delegate, name) # May raise AttributeError
setattr(self, name, attr)
- self.__cache[name] = attr
+ self.__cache.add(name)
return attr

def resetcache(self):
diff --git a/Lib/idlelib/idle_test/test_delegator.py b/Lib/idlelib/idle_test/test_delegator.py
new file mode 100644
--- /dev/null
+++ b/Lib/idlelib/idle_test/test_delegator.py
@@ -0,0 +1,37 @@
+import unittest
+from idlelib.Delegator import Delegator
+
+class DelegatorTest(unittest.TestCase):
+
+ def test_mydel(self):
+ # test a simple use scenario
+
+ # initialize
+ mydel = Delegator(int)
+ self.assertIs(mydel.delegate, int)
+ self.assertEqual(mydel._Delegator__cache, set())
+
+ # add an attribute:
+ self.assertRaises(AttributeError, mydel.__getattr__, 'xyz')
+ bl = mydel.bit_length
+ self.assertIs(bl, int.bit_length)
+ self.assertIs(mydel.__dict__['bit_length'], int.bit_length)
+ self.assertEqual(mydel._Delegator__cache, {'bit_length'})
+
+ # add a second attribute
+ mydel.numerator
+ self.assertEqual(mydel._Delegator__cache, {'bit_length', 'numerator'})
+
+ # delete the second (which, however, leaves it in the name cache)
+ del mydel.numerator
+ self.assertNotIn('numerator', mydel.__dict__)
+ self.assertIn('numerator', mydel._Delegator__cache)
+
+ # reset by calling .setdelegate, which calls .resetcache
+ mydel.setdelegate(float)
+ self.assertIs(mydel.delegate, float)
+ self.assertNotIn('bit_length', mydel.__dict__)
+ self.assertEqual(mydel._Delegator__cache, set())
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2, exit=2)

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jul 12, 2013, 5:19 PM

Post #21 of 34 (97 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/979905090779
changeset: 84604:979905090779
parent: 84600:7de05609e390
parent: 84603:8f13fb4c5826
user: Terry Jan Reedy <tjreedy [at] udel>
date: Fri Jul 12 20:10:48 2013 -0400
summary:
Merge with 3.3

files:
Lib/idlelib/idle_test/mock_tk.py | 226 ++++++++++++++++-
Lib/idlelib/idle_test/test_text.py | 228 +++++++++++++++++
2 files changed, 449 insertions(+), 5 deletions(-)


diff --git a/Lib/idlelib/idle_test/mock_tk.py b/Lib/idlelib/idle_test/mock_tk.py
--- a/Lib/idlelib/idle_test/mock_tk.py
+++ b/Lib/idlelib/idle_test/mock_tk.py
@@ -1,4 +1,5 @@
"""Classes that replace tkinter gui objects used by an object being tested.
+
A gui object is anything with a master or parent paramenter, which is typically
required in spite of what the doc strings say.
"""
@@ -15,8 +16,10 @@
return self.value

class Mbox_func:
- """Generic mock for messagebox functions. All have same call signature.
- Mbox instantiates once for each function. Tester uses attributes.
+ """Generic mock for messagebox functions, which all have the same signature.
+
+ Instead of displaying a message box, the mock's call method saves the
+ arguments as instance attributes, which test functions can then examime.
"""
def __init__(self):
self.result = None # The return for all show funcs
@@ -30,6 +33,7 @@

class Mbox:
"""Mock for tkinter.messagebox with an Mbox_func for each function.
+
This module was 'tkMessageBox' in 2.x; hence the 'import as' in 3.x.
Example usage in test_module.py for testing functios in module.py:
---
@@ -49,9 +53,9 @@
def tearDownClass(cls):
module.tkMessageBox = orig_mbox
---
- When tkMessageBox functions are the only gui making calls in a method,
- this replacement makes the method gui-free and unit-testable.
- For 'ask' functions, set func.result return before calling method.
+ For 'ask' functions, set func.result return value before calling the method
+ that uses the message function. When tkMessageBox functions are the
+ only gui alls in a method, this replacement makes the method gui-free,
"""
askokcancel = Mbox_func() # True or False
askquestion = Mbox_func() # 'yes' or 'no'
@@ -61,3 +65,215 @@
showerror = Mbox_func() # None
showinfo = Mbox_func() # None
showwarning = Mbox_func() # None
+
+from _tkinter import TclError
+
+class Text:
+ """A semi-functional non-gui replacement for tkinter.Text text editors.
+
+ The mock's data model is that a text is a list of \n-terminated lines.
+ The mock adds an empty string at the beginning of the list so that the
+ index of actual lines start at 1, as with Tk. The methods never see this.
+ Tk initializes files with a terminal \n that cannot be deleted. It is
+ invisible in the sense that one cannot move the cursor beyond it.
+
+ This class is only tested (and valid) with strings of ascii chars.
+ For testing, we are not concerned with Tk Text's treatment of,
+ for instance, 0-width characters or character + accent.
+ """
+ def __init__(self, master=None, cnf={}, **kw):
+ '''Initialize mock, non-gui, text-only Text widget.
+
+ At present, all args are ignored. Almost all affect visual behavior.
+ There are just a few Text-only options that affect text behavior.
+ '''
+ self.data = ['', '\n']
+
+ def index(self, index):
+ "Return string version of index decoded according to current text."
+ return "%s.%s" % self._decode(index, endflag=1)
+
+ def _decode(self, index, endflag=0):
+ """Return a (line, char) tuple of int indexes into self.data.
+
+ This implements .index without converting the result back to a string.
+ The result is contrained by the number of lines and linelengths of
+ self.data. For many indexes, the result is initally (1, 0).
+
+ The input index may have any of several possible forms:
+ * line.char float: converted to 'line.char' string;
+ * 'line.char' string, where line and char are decimal integers;
+ * 'line.char lineend', where lineend='lineend' (and char is ignored);
+ * 'line.end', where end='end' (same as above);
+ * 'insert', the positions before terminal \n;
+ * 'end', whose meaning depends on the endflag passed to ._endex.
+ * 'sel.first' or 'sel.last', where sel is a tag -- not implemented.
+ """
+ if isinstance(index, (float, bytes)):
+ index = str(index)
+ try:
+ index=index.lower()
+ except AttributeError:
+ raise TclError('bad text index "%s"' % index) from None
+
+ lastline = len(self.data) - 1 # same as number of text lines
+ if index == 'insert':
+ return lastline, len(self.data[lastline]) - 1
+ elif index == 'end':
+ return self._endex(endflag)
+
+ line, char = index.split('.')
+ line = int(line)
+
+ # Out of bounds line becomes first or last ('end') index
+ if line < 1:
+ return 1, 0
+ elif line > lastline:
+ return self._endex(endflag)
+
+ linelength = len(self.data[line]) -1 # position before/at \n
+ if char.endswith(' lineend') or char == 'end':
+ return line, linelength
+ # Tk requires that ignored chars before ' lineend' be valid int
+
+ # Out of bounds char becomes first or last index of line
+ char = int(char)
+ if char < 0:
+ char = 0
+ elif char > linelength:
+ char = linelength
+ return line, char
+
+ def _endex(self, endflag):
+ '''Return position for 'end' or line overflow corresponding to endflag.
+
+ -1: position before terminal \n; for .insert(), .delete
+ 0: position after terminal \n; for .get, .delete index 1
+ 1: same viewed as begininning of non-existent next line (for .index)
+ '''
+ n = len(self.data)
+ if endflag == 1:
+ return n, 0
+ else:
+ n -= 1
+ return n, len(self.data[n]) + endflag
+
+
+ def insert(self, index, chars):
+ "Insert chars before the character at index."
+
+ if not chars: # ''.splitlines() is [], not ['']
+ return
+ chars = chars.splitlines(True)
+ if chars[-1][-1] == '\n':
+ chars.append('')
+ line, char = self._decode(index, -1)
+ before = self.data[line][:char]
+ after = self.data[line][char:]
+ self.data[line] = before + chars[0]
+ self.data[line+1:line+1] = chars[1:]
+ self.data[line+len(chars)-1] += after
+
+
+ def get(self, index1, index2=None):
+ "Return slice from index1 to index2 (default is 'index1+1')."
+
+ startline, startchar = self._decode(index1)
+ if index2 is None:
+ endline, endchar = startline, startchar+1
+ else:
+ endline, endchar = self._decode(index2)
+
+ if startline == endline:
+ return self.data[startline][startchar:endchar]
+ else:
+ lines = [self.data[startline][startchar:]]
+ for i in range(startline+1, endline):
+ lines.append(self.data[i])
+ lines.append(self.data[endline][:endchar])
+ return ''.join(lines)
+
+
+ def delete(self, index1, index2=None):
+ '''Delete slice from index1 to index2 (default is 'index1+1').
+
+ Adjust default index2 ('index+1) for line ends.
+ Do not delete the terminal \n at the very end of self.data ([-1][-1]).
+ '''
+ startline, startchar = self._decode(index1, -1)
+ if index2 is None:
+ if startchar < len(self.data[startline])-1:
+ # not deleting \n
+ endline, endchar = startline, startchar+1
+ elif startline < len(self.data) - 1:
+ # deleting non-terminal \n, convert 'index1+1 to start of next line
+ endline, endchar = startline+1, 0
+ else:
+ # do not delete terminal \n if index1 == 'insert'
+ return
+ else:
+ endline, endchar = self._decode(index2, -1)
+ # restricting end position to insert position excludes terminal \n
+
+ if startline == endline and startchar < endchar:
+ self.data[startline] = self.data[startline][:startchar] + \
+ self.data[startline][endchar:]
+ elif startline < endline:
+ self.data[startline] = self.data[startline][:startchar] + \
+ self.data[endline][endchar:]
+ startline += 1
+ for i in range(startline, endline+1):
+ del self.data[startline]
+
+ def compare(self, index1, op, index2):
+ line1, char1 = self._decode(index1)
+ line2, char2 = self._decode(index2)
+ if op == '<':
+ return line1 < line2 or line1 == line2 and char1 < char2
+ elif op == '<=':
+ return line1 < line2 or line1 == line2 and char1 <= char2
+ elif op == '>':
+ return line1 > line2 or line1 == line2 and char1 > char2
+ elif op == '>=':
+ return line1 > line2 or line1 == line2 and char1 >= char2
+ elif op == '==':
+ return line1 == line2 and char1 == char2
+ elif op == '!=':
+ return line1 != line2 or char1 != char2
+ else:
+ raise TclError('''bad comparison operator "%s":'''
+ '''must be <, <=, ==, >=, >, or !=''' % op)
+
+ # The following Text methods normally do something and return None.
+ # Whether doing nothing is sufficient for a test will depend on the test.
+
+ def mark_set(self, name, index):
+ "Set mark *name* before the character at index."
+ pass
+
+ def mark_unset(self, *markNames):
+ "Delete all marks in markNames."
+
+ def tag_remove(self, tagName, index1, index2=None):
+ "Remove tag tagName from all characters between index1 and index2."
+ pass
+
+ # The following Text methods affect the graphics screen and return None.
+ # Doing nothing should always be sufficient for tests.
+
+ def scan_dragto(self, x, y):
+ "Adjust the view of the text according to scan_mark"
+
+ def scan_mark(self, x, y):
+ "Remember the current X, Y coordinates."
+
+ def see(self, index):
+ "Scroll screen to make the character at INDEX is visible."
+ pass
+
+ # The following is a Misc method inheritet by Text.
+ # It should properly go in a Misc mock, but is included here for now.
+
+ def bind(sequence=None, func=None, add=None):
+ "Bind to this widget at event sequence a call to function func."
+ pass
diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py
new file mode 100644
--- /dev/null
+++ b/Lib/idlelib/idle_test/test_text.py
@@ -0,0 +1,228 @@
+# Test mock_tk.Text class against tkinter.Text class by running same tests with both.
+import unittest
+from test.support import requires
+
+from _tkinter import TclError
+import tkinter as tk
+
+class TextTest(object):
+
+ hw = 'hello\nworld' # usual initial insert after initialization
+ hwn = hw+'\n' # \n present at initialization, before insert
+
+ Text = None
+ def setUp(self):
+ self.text = self.Text()
+
+ def test_init(self):
+ self.assertEqual(self.text.get('1.0'), '\n')
+ self.assertEqual(self.text.get('end'), '')
+
+ def test_index_empty(self):
+ index = self.text.index
+
+ for dex in (-1.0, 0.3, '1.-1', '1.0', '1.0 lineend', '1.end', '1.33',
+ 'insert'):
+ self.assertEqual(index(dex), '1.0')
+
+ for dex in 'end', 2.0, '2.1', '33.44':
+ self.assertEqual(index(dex), '2.0')
+
+ def test_index_data(self):
+ index = self.text.index
+ self.text.insert('1.0', self.hw)
+
+ for dex in -1.0, 0.3, '1.-1', '1.0':
+ self.assertEqual(index(dex), '1.0')
+
+ for dex in '1.0 lineend', '1.end', '1.33':
+ self.assertEqual(index(dex), '1.5')
+
+ for dex in 'end', '33.44':
+ self.assertEqual(index(dex), '3.0')
+
+ def test_get(self):
+ get = self.text.get
+ Equal = self.assertEqual
+ self.text.insert('1.0', self.hw)
+
+ Equal(get('end'), '')
+ Equal(get('end', 'end'), '')
+ Equal(get('1.0'), 'h')
+ Equal(get('1.0', '1.1'), 'h')
+ Equal(get('1.0', '1.3'), 'hel')
+ Equal(get('1.1', '1.3'), 'el')
+ Equal(get('1.0', '1.0 lineend'), 'hello')
+ Equal(get('1.0', '1.10'), 'hello')
+ Equal(get('1.0 lineend'), '\n')
+ Equal(get('1.1', '2.3'), 'ello\nwor')
+ Equal(get('1.0', '2.5'), self.hw)
+ Equal(get('1.0', 'end'), self.hwn)
+ Equal(get('0.0', '5.0'), self.hwn)
+
+ def test_insert(self):
+ insert = self.text.insert
+ get = self.text.get
+ Equal = self.assertEqual
+
+ insert('1.0', self.hw)
+ Equal(get('1.0', 'end'), self.hwn)
+
+ insert('1.0', '') # nothing
+ Equal(get('1.0', 'end'), self.hwn)
+
+ insert('1.0', '*')
+ Equal(get('1.0', 'end'), '*hello\nworld\n')
+
+ insert('1.0 lineend', '*')
+ Equal(get('1.0', 'end'), '*hello*\nworld\n')
+
+ insert('2.3', '*')
+ Equal(get('1.0', 'end'), '*hello*\nwor*ld\n')
+
+ insert('end', 'x')
+ Equal(get('1.0', 'end'), '*hello*\nwor*ldx\n')
+
+ insert('1.4', 'x\n')
+ Equal(get('1.0', 'end'), '*helx\nlo*\nwor*ldx\n')
+
+ def test_no_delete(self):
+ # if index1 == 'insert' or 'end' or >= end, there is no deletion
+ delete = self.text.delete
+ get = self.text.get
+ Equal = self.assertEqual
+ self.text.insert('1.0', self.hw)
+
+ delete('insert')
+ Equal(get('1.0', 'end'), self.hwn)
+
+ delete('end')
+ Equal(get('1.0', 'end'), self.hwn)
+
+ delete('insert', 'end')
+ Equal(get('1.0', 'end'), self.hwn)
+
+ delete('insert', '5.5')
+ Equal(get('1.0', 'end'), self.hwn)
+
+ delete('1.4', '1.0')
+ Equal(get('1.0', 'end'), self.hwn)
+
+ delete('1.4', '1.4')
+ Equal(get('1.0', 'end'), self.hwn)
+
+ def test_delete_char(self):
+ delete = self.text.delete
+ get = self.text.get
+ Equal = self.assertEqual
+ self.text.insert('1.0', self.hw)
+
+ delete('1.0')
+ Equal(get('1.0', '1.end'), 'ello')
+
+ delete('1.0', '1.1')
+ Equal(get('1.0', '1.end'), 'llo')
+
+ # delete \n and combine 2 lines into 1
+ delete('1.end')
+ Equal(get('1.0', '1.end'), 'lloworld')
+
+ self.text.insert('1.3', '\n')
+ delete('1.10')
+ Equal(get('1.0', '1.end'), 'lloworld')
+
+ self.text.insert('1.3', '\n')
+ delete('1.3', '2.0')
+ Equal(get('1.0', '1.end'), 'lloworld')
+
+ def test_delete_slice(self):
+ delete = self.text.delete
+ get = self.text.get
+ Equal = self.assertEqual
+ self.text.insert('1.0', self.hw)
+
+ delete('1.0', '1.0 lineend')
+ Equal(get('1.0', 'end'), '\nworld\n')
+
+ delete('1.0', 'end')
+ Equal(get('1.0', 'end'), '\n')
+
+ self.text.insert('1.0', self.hw)
+ delete('1.0', '2.0')
+ Equal(get('1.0', 'end'), 'world\n')
+
+ delete('1.0', 'end')
+ Equal(get('1.0', 'end'), '\n')
+
+ self.text.insert('1.0', self.hw)
+ delete('1.2', '2.3')
+ Equal(get('1.0', 'end'), 'held\n')
+
+ def test_multiple_lines(self): # insert and delete
+ self.text.insert('1.0', 'hello')
+
+ self.text.insert('1.3', '1\n2\n3\n4\n5')
+ self.assertEqual(self.text.get('1.0', 'end'), 'hel1\n2\n3\n4\n5lo\n')
+
+ self.text.delete('1.3', '5.1')
+ self.assertEqual(self.text.get('1.0', 'end'), 'hello\n')
+
+ def test_compare(self):
+ compare = self.text.compare
+ Equal = self.assertEqual
+ # need data so indexes not squished to 1,0
+ self.text.insert('1.0', 'First\nSecond\nThird\n')
+
+ self.assertRaises(TclError, compare, '2.2', 'op', '2.2')
+
+ for op, less1, less0, equal, greater0, greater1 in (
+ ('<', True, True, False, False, False),
+ ('<=', True, True, True, False, False),
+ ('>', False, False, False, True, True),
+ ('>=', False, False, True, True, True),
+ ('==', False, False, True, False, False),
+ ('!=', True, True, False, True, True),
+ ):
+ Equal(compare('1.1', op, '2.2'), less1, op)
+ Equal(compare('2.1', op, '2.2'), less0, op)
+ Equal(compare('2.2', op, '2.2'), equal, op)
+ Equal(compare('2.3', op, '2.2'), greater0, op)
+ Equal(compare('3.3', op, '2.2'), greater1, op)
+
+
+class MockTextTest(TextTest, unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ from idlelib.idle_test.mock_tk import Text
+ cls.Text = Text
+
+ def test_decode(self):
+ # test endflags (-1, 0) not tested by test_index (which uses +1)
+ decode = self.text._decode
+ Equal = self.assertEqual
+ self.text.insert('1.0', self.hw)
+
+ Equal(decode('end', -1), (2, 5))
+ Equal(decode('3.1', -1), (2, 5))
+ Equal(decode('end', 0), (2, 6))
+ Equal(decode('3.1', 0), (2, 6))
+
+
+class TkTextTest(TextTest, unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ from tkinter import Tk, Text
+ cls.Text = Text
+ cls.root = Tk()
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.root.destroy()
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2, exit=False)
+

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jul 12, 2013, 5:19 PM

Post #22 of 34 (97 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/514cb18945aa
changeset: 84606:514cb18945aa
parent: 84604:979905090779
parent: 84605:5611d3a954f8
user: Terry Jan Reedy <tjreedy [at] udel>
date: Fri Jul 12 20:17:00 2013 -0400
summary:
Merge with 3.3

files:
Lib/idlelib/idle_test/mock_tk.py | 12 ++++++------
Lib/idlelib/idle_test/test_text.py | 3 +--
2 files changed, 7 insertions(+), 8 deletions(-)


diff --git a/Lib/idlelib/idle_test/mock_tk.py b/Lib/idlelib/idle_test/mock_tk.py
--- a/Lib/idlelib/idle_test/mock_tk.py
+++ b/Lib/idlelib/idle_test/mock_tk.py
@@ -210,7 +210,7 @@
endline, endchar = startline+1, 0
else:
# do not delete terminal \n if index1 == 'insert'
- return
+ return
else:
endline, endchar = self._decode(index2, -1)
# restricting end position to insert position excludes terminal \n
@@ -219,11 +219,11 @@
self.data[startline] = self.data[startline][:startchar] + \
self.data[startline][endchar:]
elif startline < endline:
- self.data[startline] = self.data[startline][:startchar] + \
- self.data[endline][endchar:]
- startline += 1
- for i in range(startline, endline+1):
- del self.data[startline]
+ self.data[startline] = self.data[startline][:startchar] + \
+ self.data[endline][endchar:]
+ startline += 1
+ for i in range(startline, endline+1):
+ del self.data[startline]

def compare(self, index1, op, index2):
line1, char1 = self._decode(index1)
diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py
--- a/Lib/idlelib/idle_test/test_text.py
+++ b/Lib/idlelib/idle_test/test_text.py
@@ -36,7 +36,7 @@
self.assertEqual(index(dex), '1.0')

for dex in '1.0 lineend', '1.end', '1.33':
- self.assertEqual(index(dex), '1.5')
+ self.assertEqual(index(dex), '1.5')

for dex in 'end', '33.44':
self.assertEqual(index(dex), '3.0')
@@ -225,4 +225,3 @@

if __name__ == '__main__':
unittest.main(verbosity=2, exit=False)
-

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jul 12, 2013, 11:35 PM

Post #23 of 34 (97 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/ffd923b388d8
changeset: 84614:ffd923b388d8
parent: 84609:da7d97ca1ef6
parent: 84613:22ce68d98345
user: Terry Jan Reedy <tjreedy [at] udel>
date: Sat Jul 13 02:35:07 2013 -0400
summary:
Merge with 3.3

files:
Lib/idlelib/RstripExtension.py | 20 +++--
Lib/idlelib/idle_test/mock_idle.py | 27 ++++++++
Lib/idlelib/idle_test/test_rstrip.py | 49 ++++++++++++++++
Misc/ACKS | 1 +
Misc/NEWS | 5 +
5 files changed, 94 insertions(+), 8 deletions(-)


diff --git a/Lib/idlelib/RstripExtension.py b/Lib/idlelib/RstripExtension.py
--- a/Lib/idlelib/RstripExtension.py
+++ b/Lib/idlelib/RstripExtension.py
@@ -1,13 +1,9 @@
'Provides "Strip trailing whitespace" under the "Format" menu.'

-__author__ = "Roger D. Serwy <roger.serwy at gmail.com>"
-
class RstripExtension:

menudefs = [
- ('format', [None,
- ('Strip trailing whitespace', '<<do-rstrip>>'),
- ]),]
+ ('format', [None, ('Strip trailing whitespace', '<<do-rstrip>>'), ] ), ]

def __init__(self, editwin):
self.editwin = editwin
@@ -20,10 +16,18 @@

undo.undo_block_start()

- end_line = int(float(text.index('end'))) + 1
+ end_line = int(float(text.index('end')))
for cur in range(1, end_line):
- txt = text.get('%i.0' % cur, '%i.0 lineend' % cur)
+ txt = text.get('%i.0' % cur, '%i.end' % cur)
+ raw = len(txt)
cut = len(txt.rstrip())
- text.delete('%i.%i' % (cur, cut), '%i.0 lineend' % cur)
+ # Since text.delete() marks file as changed, even if not,
+ # only call it when needed to actually delete something.
+ if cut < raw:
+ text.delete('%i.%i' % (cur, cut), '%i.end' % cur)

undo.undo_block_stop()
+
+if __name__ == "__main__":
+ import unittest
+ unittest.main('idlelib.idle_test.test_rstrip', verbosity=2, exit=False)
diff --git a/Lib/idlelib/idle_test/mock_idle.py b/Lib/idlelib/idle_test/mock_idle.py
new file mode 100644
--- /dev/null
+++ b/Lib/idlelib/idle_test/mock_idle.py
@@ -0,0 +1,27 @@
+'''Mock classes that imitate idlelib modules or classes.
+
+Attributes and methods will be added as needed for tests.
+'''
+
+from idlelib.idle_test.mock_tk import Text
+
+class Editor:
+ '''Minimally imitate EditorWindow.EditorWindow class.
+ '''
+ def __init__(self, flist=None, filename=None, key=None, root=None):
+ self.text = Text()
+ self.undo = UndoDelegator()
+
+ def get_selection_indices(self):
+ first = self.text.index('1.0')
+ last = self.text.index('end')
+ return first, last
+
+class UndoDelegator:
+ '''Minimally imitate UndoDelegator,UndoDelegator class.
+ '''
+ # A real undo block is only needed for user interaction.
+ def undo_block_start(*args):
+ pass
+ def undo_block_stop(*args):
+ pass
diff --git a/Lib/idlelib/idle_test/test_rstrip.py b/Lib/idlelib/idle_test/test_rstrip.py
new file mode 100644
--- /dev/null
+++ b/Lib/idlelib/idle_test/test_rstrip.py
@@ -0,0 +1,49 @@
+import unittest
+import idlelib.RstripExtension as rs
+from idlelib.idle_test.mock_idle import Editor
+
+class rstripTest(unittest.TestCase):
+
+ def test_rstrip_line(self):
+ editor = Editor()
+ text = editor.text
+ do_rstrip = rs.RstripExtension(editor).do_rstrip
+
+ do_rstrip()
+ self.assertEqual(text.get('1.0', 'insert'), '')
+ text.insert('1.0', ' ')
+ do_rstrip()
+ self.assertEqual(text.get('1.0', 'insert'), '')
+ text.insert('1.0', ' \n')
+ do_rstrip()
+ self.assertEqual(text.get('1.0', 'insert'), '\n')
+
+ def test_rstrip_multiple(self):
+ editor = Editor()
+ # Uncomment following to verify that test passes with real widgets.
+## from idlelib.EditorWindow import EditorWindow as Editor
+## from tkinter import Tk
+## editor = Editor(root=Tk())
+ text = editor.text
+ do_rstrip = rs.RstripExtension(editor).do_rstrip
+
+ original = (
+ "Line with an ending tab \n"
+ "Line ending in 5 spaces \n"
+ "Linewithnospaces\n"
+ " indented line\n"
+ " indented line with trailing space \n"
+ " ")
+ stripped = (
+ "Line with an ending tab\n"
+ "Line ending in 5 spaces\n"
+ "Linewithnospaces\n"
+ " indented line\n"
+ " indented line with trailing space\n")
+
+ text.insert('1.0', original)
+ do_rstrip()
+ self.assertEqual(text.get('1.0', 'insert'), stripped)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2, exit=False)
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1339,6 +1339,7 @@
Henrik Weber
Corran Webster
Glyn Webster
+Phil Webster
Stefan Wehr
Zack Weinberg
Bob Weiner
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -601,6 +601,10 @@
IDLE
----

+- Issue #18279: Format - Strip trailing whitespace no longer marks a file as
+ changed when it has not been changed. This fix followed the addition of a
+ test file originally written by Phil Webster (the issue's main goal).
+
- Issue #7136: In the Idle File menu, "New Window" is renamed "New File".
Patch by Tal Einat, Roget Serwy, and Todd Rovito.

@@ -617,6 +621,7 @@

- Issue #15392: Create a unittest framework for IDLE.
Initial patch by Rajagopalasarma Jayakrishnan.
+ See Lib/idlelib/idle_test/README.txt for how to run Idle tests.

- Issue #14146: Highlight source line while debugging on Windows.


--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jul 13, 2013, 1:07 AM

Post #24 of 34 (97 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/f478eb9adfe0
changeset: 84616:f478eb9adfe0
parent: 84614:ffd923b388d8
parent: 84615:bc3a34e47923
user: Terry Jan Reedy <tjreedy [at] udel>
date: Sat Jul 13 04:06:03 2013 -0400
summary:
Merge with 3.3

files:
Lib/idlelib/idle_test/test_text.py | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)


diff --git a/Lib/idlelib/idle_test/test_text.py b/Lib/idlelib/idle_test/test_text.py
--- a/Lib/idlelib/idle_test/test_text.py
+++ b/Lib/idlelib/idle_test/test_text.py
@@ -216,7 +216,10 @@
requires('gui')
from tkinter import Tk, Text
cls.Text = Text
- cls.root = Tk()
+ try:
+ cls.root = Tk()
+ except TclError as msg:
+ raise unittest.SkipTest('TclError: %s' % msg)

@classmethod
def tearDownClass(cls):

--
Repository URL: http://hg.python.org/cpython


python-checkins at python

Jul 21, 2013, 6:14 PM

Post #25 of 34 (85 views)
Permalink
cpython (merge 3.3 -> default): Merge with 3.3 [In reply to]

http://hg.python.org/cpython/rev/bf9ccd08f559
changeset: 84774:bf9ccd08f559
parent: 84771:fe88b7949fbe
parent: 84773:26686d227e41
user: Terry Jan Reedy <tjreedy [at] udel>
date: Sun Jul 21 20:58:15 2013 -0400
summary:
Merge with 3.3

files:
Misc/NEWS | 2 ++
Tools/scripts/patchcheck.py | 11 ++++++-----
2 files changed, 8 insertions(+), 5 deletions(-)


diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -695,6 +695,8 @@
Tools/Demos
-----------

+- Issue #18439: Make patchcheck work on Windows for ACKS, NEWS.
+
- Issue #18448: Fix a typo in Tools/demo/eiffel.py.

- Issue #18457: Fixed saving of formulas and complex numbers in
diff --git a/Tools/scripts/patchcheck.py b/Tools/scripts/patchcheck.py
--- a/Tools/scripts/patchcheck.py
+++ b/Tools/scripts/patchcheck.py
@@ -124,13 +124,13 @@
@status("Misc/ACKS updated", modal=True)
def credit_given(file_paths):
"""Check if Misc/ACKS has been changed."""
- return 'Misc/ACKS' in file_paths
+ return os.path.join('Misc', 'ACKS') in file_paths


@status("Misc/NEWS updated", modal=True)
def reported_news(file_paths):
"""Check if Misc/NEWS has been changed."""
- return 'Misc/NEWS' in file_paths
+ return os.path.join('Misc', 'NEWS') in file_paths

@status("configure regenerated", modal=True, info=str)
def regenerated_configure(file_paths):
@@ -153,7 +153,8 @@
python_files = [fn for fn in file_paths if fn.endswith('.py')]
c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))]
doc_files = [fn for fn in file_paths if fn.startswith('Doc')]
- special_files = {'Misc/ACKS', 'Misc/NEWS'} & set(file_paths)
+ misc_files = {os.path.join('Misc', 'ACKS'), os.path.join('Misc', 'NEWS')}\
+ & set(file_paths)
# PEP 8 whitespace rules enforcement.
normalize_whitespace(python_files)
# C rules enforcement.
@@ -163,9 +164,9 @@
# Docs updated.
docs_modified(doc_files)
# Misc/ACKS changed.
- credit_given(special_files)
+ credit_given(misc_files)
# Misc/NEWS changed.
- reported_news(special_files)
+ reported_news(misc_files)
# Regenerated configure, if necessary.
regenerated_configure(file_paths)
# Regenerated pyconfig.h.in, if necessary.

--
Repository URL: http://hg.python.org/cpython

First page Previous page 1 2 Next page Last page  View All Python checkins RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.