diff options
author | Brian Curtin <brian@python.org> | 2011-06-13 21:10:32 (GMT) |
---|---|---|
committer | Brian Curtin <brian@python.org> | 2011-06-13 21:10:32 (GMT) |
commit | a87d586fd6c4a5dfe4ea89fda288ae8eb66b0134 (patch) | |
tree | 420fe483c679d2225cc8bd82eefaecf783999268 | |
parent | d25aef55c8b0025dd2ee7de11b526f34ceed6b66 (diff) | |
parent | cdc751720ee7a13ac163da1eedf3a513386c98d4 (diff) | |
download | cpython-a87d586fd6c4a5dfe4ea89fda288ae8eb66b0134.zip cpython-a87d586fd6c4a5dfe4ea89fda288ae8eb66b0134.tar.gz cpython-a87d586fd6c4a5dfe4ea89fda288ae8eb66b0134.tar.bz2 |
branch merge?
-rw-r--r-- | .hgtags | 1 | ||||
-rw-r--r-- | Doc/c-api/intro.rst | 4 | ||||
-rw-r--r-- | Doc/distutils/introduction.rst | 10 | ||||
-rw-r--r-- | Doc/documenting/markup.rst | 11 | ||||
-rw-r--r-- | Doc/install/index.rst | 15 | ||||
-rw-r--r-- | Doc/library/builtins.rst | 4 | ||||
-rw-r--r-- | Doc/library/constants.rst | 2 | ||||
-rw-r--r-- | Doc/library/logging.handlers.rst | 15 | ||||
-rw-r--r-- | Doc/library/logging.rst | 10 | ||||
-rw-r--r-- | Doc/license.rst | 4 | ||||
-rw-r--r-- | Doc/tutorial/interpreter.rst | 2 | ||||
-rw-r--r-- | Doc/using/cmdline.rst | 2 | ||||
-rw-r--r-- | Lib/idlelib/config-main.def | 4 | ||||
-rw-r--r-- | Lib/inspect.py | 8 | ||||
-rw-r--r-- | Lib/logging/handlers.py | 6 | ||||
-rw-r--r-- | Lib/netrc.py | 12 | ||||
-rw-r--r-- | Lib/ntpath.py | 11 | ||||
-rwxr-xr-x | Lib/smtplib.py | 2 | ||||
-rw-r--r-- | Lib/test/support.py | 5 | ||||
-rw-r--r-- | Lib/test/test_inspect.py | 17 | ||||
-rw-r--r-- | Lib/test/test_netrc.py | 131 | ||||
-rw-r--r-- | Lib/test/test_smtplib.py | 15 | ||||
-rw-r--r-- | Lib/test/test_zipfile.py | 18 | ||||
-rw-r--r-- | Lib/zipfile.py | 18 | ||||
-rw-r--r-- | Misc/ACKS | 1 | ||||
-rw-r--r-- | Misc/NEWS | 15 | ||||
-rw-r--r-- | Modules/posixmodule.c | 40 |
27 files changed, 303 insertions, 80 deletions
@@ -76,6 +76,7 @@ a69a031ac1402dede8b1ef80096436bca6d371f3 v3.1 d18e9d71f369d8211f6ac87252c6d3211f9bd09f v3.1.3rc1 a4f75773c0060cee38b0bb651a7aba6f56b0e996 v3.1.3 32fcb9e94985cb19ce37ba9543f091c0dbe9d7dd v3.1.4rc1 +c918ec9f3a76d6afedfbb5d455004de880443a3d v3.1.4 b37b7834757492d009b99cf0ca4d42d2153d7fac v3.2a1 56d4373cecb73c8b45126ba7b045b3c7b3f94b0b v3.2a2 da012d9a2c23d144e399d2e01a55b8a83ad94573 v3.2a3 diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 83b98f9..843707d 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -588,8 +588,8 @@ frequently-used builds will be described in the remainder of this section. Compiling the interpreter with the :c:macro:`Py_DEBUG` macro defined produces what is generally meant by "a debug build" of Python. :c:macro:`Py_DEBUG` is -enabled in the Unix build by adding :option:`--with-pydebug` to the -:file:`configure` command. It is also implied by the presence of the +enabled in the Unix build by adding ``--with-pydebug`` to the +:file:`./configure` command. It is also implied by the presence of the not-Python-specific :c:macro:`_DEBUG` macro. When :c:macro:`Py_DEBUG` is enabled in the Unix build, compiler optimization is disabled. diff --git a/Doc/distutils/introduction.rst b/Doc/distutils/introduction.rst index 8dc604d..57d34a4 100644 --- a/Doc/distutils/introduction.rst +++ b/Doc/distutils/introduction.rst @@ -79,11 +79,17 @@ Some observations: for an example) To create a source distribution for this module, you would create a setup -script, :file:`setup.py`, containing the above code, and run:: +script, :file:`setup.py`, containing the above code, and run this command from a +terminal:: python setup.py sdist -which will create an archive file (e.g., tarball on Unix, ZIP file on Windows) +For Windows, open a command prompt windows ("DOS box") and change the command +to:: + + setup.py sdist + +:command:`sdist` will create an archive file (e.g., tarball on Unix, ZIP file on Windows) containing your setup script :file:`setup.py`, and your module :file:`foo.py`. The archive file will be named :file:`foo-1.0.tar.gz` (or :file:`.zip`), and will unpack into a directory :file:`foo-1.0`. diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst index 57d9eeb..c005d0c 100644 --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -98,11 +98,12 @@ following example shows all of the features of this directive type:: Spam or ham the foo. -The signatures of object methods or data attributes should always include the -type name (``.. method:: FileInput.input(...)``), even if it is obvious from the -context which type they belong to; this is to enable consistent -cross-references. If you describe methods belonging to an abstract protocol, -such as "context managers", include a (pseudo-)type name too to make the +The signatures of object methods or data attributes should not include the +class name, but be nested in a class directive. The generated files will +reflect this nesting, and the target identifiers (for HTML output) will use +both the class and method name, to enable consistent cross-references. If you +describe methods belonging to an abstract protocol such as context managers, +use a class directive with a (pseudo-)type name too to make the index entries more informative. The directives are: diff --git a/Doc/install/index.rst b/Doc/install/index.rst index 31c1d7f..f8d6305 100644 --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -96,10 +96,16 @@ in the name of the downloaded archive, e.g. :file:`foo-1.0.tar.gz` or directory: :file:`foo-1.0` or :file:`widget-0.9.7`. Additionally, the distribution will contain a setup script :file:`setup.py`, and a file named :file:`README.txt` or possibly just :file:`README`, which should explain that -building and installing the module distribution is a simple matter of running :: +building and installing the module distribution is a simple matter of running +one command from a terminal:: python setup.py install +For Windows, this command should be run from a command prompt windows ("DOS +box"):: + + setup.py install + If all these things are true, then you already know how to build and install the modules you've just downloaded: Run the command above. Unless you need to install things in a non-standard way or customize the build process, you don't @@ -113,14 +119,11 @@ Standard Build and Install ========================== As described in section :ref:`inst-new-standard`, building and installing a module -distribution using the Distutils is usually one simple command:: +distribution using the Distutils is usually one simple command to run from a +terminal:: python setup.py install -On Unix, you'd run this command from a shell prompt; on Windows, you have to -open a command prompt window ("DOS box") and do it there; on Mac OS X, you open -a :command:`Terminal` window to get a shell prompt. - .. _inst-platform-variations: diff --git a/Doc/library/builtins.rst b/Doc/library/builtins.rst index c495728..d4199d2 100644 --- a/Doc/library/builtins.rst +++ b/Doc/library/builtins.rst @@ -7,7 +7,9 @@ This module provides direct access to all 'built-in' identifiers of Python; for example, ``builtins.open`` is the full name for the built-in function -:func:`open`. +:func:`open`. See :ref:`built-in-funcs` and :ref:`built-in-consts` for +documentation. + This module is not normally accessed explicitly by most applications, but can be useful in modules that provide objects with the same name as a built-in value, diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst index 51a1c26..fa61f68 100644 --- a/Doc/library/constants.rst +++ b/Doc/library/constants.rst @@ -1,3 +1,5 @@ +.. _built-in-consts: + Built-in Constants ================== diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index eda9302..378c071 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -436,6 +436,21 @@ supports sending logging messages to a remote or local Unix syslog. The record is formatted, and then sent to the syslog server. If exception information is present, it is *not* sent to the server. + .. versionchanged:: 3.2.1 + (See: :issue:`12168`.) In earlier versions, the message sent to the + syslog daemons was always terminated with a NUL byte, because early + versions of these daemons expected a NUL terminated message - even + though it's not in the relevant specification (RF 5424). More recent + versions of these daemons don't expect the NUL byte but strip it off + if it's there, and even more recent daemons (which adhere more closely + to RFC 5424) pass the NUL byte on as part of the message. + + To enable easier handling of syslog messages in the face of all these + differing daemon behaviours, the appending of the NUL byte has been + made configurable, through the use of a class-level attribute, + ``append_nul``. This defaults to ``True`` (preserving the existing + behaviour) but can be set to ``False`` on a ``SysLogHandler`` instance + in order for that instance to *not* append the NUL terminator. .. method:: encodePriority(facility, priority) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index 32f762d..20cd57c 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -453,6 +453,13 @@ The useful mapping keys in a :class:`LogRecord` are given in the section on record. Otherwise, the ISO8601 format is used. The resulting string is returned. + This function uses a user-configurable function to convert the creation + time to a tuple. By default, :func:`time.localtime` is used; to change + this for a particular formatter instance, set the ``converter`` attribute + to a function with the same signature as :func:`time.localtime` or + :func:`time.gmtime`. To change it for all formatters, for example if you + want all logging times to be shown in GMT, set the ``converter`` + attribute in the ``Formatter`` class. .. method:: formatException(exc_info) @@ -544,6 +551,9 @@ wire). :param name: The name of the logger used to log the event represented by this LogRecord. :param level: The numeric level of the logging event (one of DEBUG, INFO etc.) + Note that this is converted to *two* attributes of the LogRecord: + ``levelno`` for the numeric value and ``levelname`` for the + corresponding level name. :param pathname: The full pathname of the source file where the logging call was made. :param lineno: The line number in the source file where the logging call was diff --git a/Doc/license.rst b/Doc/license.rst index a32b7ab..b471828 100644 --- a/Doc/license.rst +++ b/Doc/license.rst @@ -845,7 +845,7 @@ expat ----- The :mod:`pyexpat` extension is built using an included copy of the expat -sources unless the build is configured :option:`--with-system-expat`:: +sources unless the build is configured ``--with-system-expat``:: Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd and Clark Cooper @@ -874,7 +874,7 @@ libffi ------ The :mod:`_ctypes` extension is built using an included copy of the libffi -sources unless the build is configured :option:`--with-system-libffi`:: +sources unless the build is configured ``--with-system-libffi``:: Copyright (c) 1996-2008 Red Hat, Inc and others. diff --git a/Doc/tutorial/interpreter.rst b/Doc/tutorial/interpreter.rst index 8d743de..29afc50 100644 --- a/Doc/tutorial/interpreter.rst +++ b/Doc/tutorial/interpreter.rst @@ -169,6 +169,8 @@ also be ``.pyw``, in that case, the console window that normally appears is suppressed. +.. _tut-source-encoding: + Source Code Encoding -------------------- diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index d1f47eb..16a753c 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -501,7 +501,7 @@ Debug-mode variables ~~~~~~~~~~~~~~~~~~~~ Setting these variables only has an effect in a debug build of Python, that is, -if Python was configured with the :option:`--with-pydebug` build option. +if Python was configured with the ``--with-pydebug`` build option. .. envvar:: PYTHONTHREADDEBUG diff --git a/Lib/idlelib/config-main.def b/Lib/idlelib/config-main.def index 5ddd098..9546e2b 100644 --- a/Lib/idlelib/config-main.def +++ b/Lib/idlelib/config-main.def @@ -46,8 +46,8 @@ [General] editor-on-startup= 0 autosave= 0 -print-command-posix=lpr %s -print-command-win=start /min notepad /p %s +print-command-posix=lpr %%s +print-command-win=start /min notepad /p %%s delete-exitfunc= 1 [EditorWindow] diff --git a/Lib/inspect.py b/Lib/inspect.py index 4899cbf..bb46ea6 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -518,9 +518,13 @@ def findsource(object): or code object. The source code is returned as a list of all the lines in the file and the line number indexes a line in that list. An IOError is raised if the source code cannot be retrieved.""" - file = getsourcefile(object) - if not file: + + file = getfile(object) + sourcefile = getsourcefile(object) + if not sourcefile and file[0] + file[-1] != '<>': raise IOError('source code not available') + file = sourcefile if sourcefile else file + module = getmodule(object, file) if module: lines = linecache.getlines(file, module.__dict__) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 306cf86..4a6b959 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -766,6 +766,8 @@ class SysLogHandler(logging.Handler): """ return self.priority_map.get(levelName, "warning") + append_nul = True # some old syslog daemons expect a NUL terminator + def emit(self, record): """ Emit a record. @@ -773,7 +775,9 @@ class SysLogHandler(logging.Handler): The record is formatted, and then sent to the syslog server. If exception information is present, it is NOT sent to the server. """ - msg = self.format(record) + '\000' + msg = self.format(record) + if self.append_nul: + msg += '\000' """ We need to convert record level to lowercase, maybe this will change in the future. diff --git a/Lib/netrc.py b/Lib/netrc.py index a60b8b7..c96db6f 100644 --- a/Lib/netrc.py +++ b/Lib/netrc.py @@ -2,7 +2,7 @@ # Module and documentation by Eric S. Raymond, 21 Dec 1998 -import os, shlex +import io, os, shlex __all__ = ["netrc", "NetrcParseError"] @@ -37,12 +37,14 @@ class netrc: lexer.commenters = lexer.commenters.replace('#', '') while 1: # Look for a machine, default, or macdef top-level keyword + saved_lineno = lexer.lineno toplevel = tt = lexer.get_token() if not tt: break elif tt[0] == '#': - fp.readline(); - continue; + if lexer.lineno == saved_lineno and len(tt) == 1: + lexer.instream.readline() + continue elif tt == 'machine': entryname = lexer.get_token() elif tt == 'default': @@ -68,8 +70,8 @@ class netrc: self.hosts[entryname] = {} while 1: tt = lexer.get_token() - if (tt=='' or tt == 'machine' or - tt == 'default' or tt =='macdef'): + if (tt.startswith('#') or + tt in {'', 'machine', 'default', 'macdef'}): if password: self.hosts[entryname] = (login, account, password) lexer.push_token(tt) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index ec8a7ab..826be87 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -672,3 +672,14 @@ except ImportError: def sameopenfile(f1, f2): """Test whether two file objects reference the same file""" return _getfileinformation(f1) == _getfileinformation(f2) + + +try: + # The genericpath.isdir implementation uses os.stat and checks the mode + # attribute to tell whether or not the path is a directory. + # This is overkill on Windows - just pass the path to GetFileAttributes + # and check the attribute from there. + from nt import _isdir as isdir +except ImportError: + # Use genericpath.isdir as imported above. + pass diff --git a/Lib/smtplib.py b/Lib/smtplib.py index dbccf48..ce71699 100755 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -162,7 +162,7 @@ def quotedata(data): re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data)) def _quote_periods(bindata): - return re.sub(br'(?m)^\.', '..', bindata) + return re.sub(br'(?m)^\.', b'..', bindata) def _fix_eols(data): return re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data) diff --git a/Lib/test/support.py b/Lib/test/support.py index 9c8f6d3..25aab2e 100644 --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -1487,11 +1487,14 @@ def can_symlink(): global _can_symlink if _can_symlink is not None: return _can_symlink + symlink_path = TESTFN + "can_symlink" try: - os.symlink(TESTFN, TESTFN + "can_symlink") + os.symlink(TESTFN, symlink_path) can = True except (OSError, NotImplementedError, AttributeError): can = False + else: + os.remove(symlink_path) _can_symlink = can return can diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index f5dff1e..7666fe4 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -298,6 +298,23 @@ class TestRetrievingSourceCode(GetSourceBase): del sys.modules[name] inspect.getmodule(compile('a=10','','single')) + def test_proceed_with_fake_filename(self): + '''doctest monkeypatches linecache to enable inspection''' + fn, source = '<test>', 'def x(): pass\n' + getlines = linecache.getlines + def monkey(filename, module_globals=None): + if filename == fn: + return source.splitlines(True) + else: + return getlines(filename, module_globals) + linecache.getlines = monkey + try: + ns = {} + exec(compile(source, fn, 'single'), ns) + inspect.getsource(ns["x"]) + finally: + linecache.getlines = getlines + class TestDecorators(GetSourceBase): fodderModule = mod2 diff --git a/Lib/test/test_netrc.py b/Lib/test/test_netrc.py index da7ec05..ef70e37 100644 --- a/Lib/test/test_netrc.py +++ b/Lib/test/test_netrc.py @@ -1,54 +1,107 @@ - -import netrc, os, unittest, sys +import netrc, os, unittest, sys, textwrap from test import support -TEST_NETRC = """ - - #this is a comment -#this is a comment -# this is a comment - -machine foo login log1 password pass1 account acct1 -machine bar login log1 password pass# account acct1 - -macdef macro1 -line1 -line2 - -macdef macro2 -line3 -line4 - -default login log2 password pass2 - -""" - temp_filename = support.TESTFN class NetrcTestCase(unittest.TestCase): - def setUp(self): - mode = 'w' - if sys.platform not in ['cygwin']: - mode += 't' - fp = open(temp_filename, mode) - fp.write(TEST_NETRC) - fp.close() - self.nrc = netrc.netrc(temp_filename) - def tearDown(self): os.unlink(temp_filename) - def test_case_1(self): - self.assertEqual(self.nrc.hosts['foo'], ('log1', 'acct1', 'pass1')) - self.assertEqual(self.nrc.hosts['default'], ('log2', None, 'pass2')) + def make_nrc(self, test_data): + test_data = textwrap.dedent(test_data) + mode = 'w' + if sys.platform != 'cygwin': + mode += 't' + with open(temp_filename, mode) as fp: + fp.write(test_data) + return netrc.netrc(temp_filename) + + def test_default(self): + nrc = self.make_nrc("""\ + machine host1.domain.com login log1 password pass1 account acct1 + default login log2 password pass2 + """) + self.assertEqual(nrc.hosts['host1.domain.com'], + ('log1', 'acct1', 'pass1')) + self.assertEqual(nrc.hosts['default'], ('log2', None, 'pass2')) def test_macros(self): - self.assertEqual(self.nrc.macros, {'macro1':['line1\n', 'line2\n'], - 'macro2':['line3\n', 'line4\n']}) + nrc = self.make_nrc("""\ + macdef macro1 + line1 + line2 + + macdef macro2 + line3 + line4 + """) + self.assertEqual(nrc.macros, {'macro1': ['line1\n', 'line2\n'], + 'macro2': ['line3\n', 'line4\n']}) + + def _test_passwords(self, nrc, passwd): + nrc = self.make_nrc(nrc) + self.assertEqual(nrc.hosts['host.domain.com'], ('log', 'acct', passwd)) + + def test_password_with_leading_hash(self): + self._test_passwords("""\ + machine host.domain.com login log password #pass account acct + """, '#pass') + + def test_password_with_trailing_hash(self): + self._test_passwords("""\ + machine host.domain.com login log password pass# account acct + """, 'pass#') + + def test_password_with_internal_hash(self): + self._test_passwords("""\ + machine host.domain.com login log password pa#ss account acct + """, 'pa#ss') + + def _test_comment(self, nrc, passwd='pass'): + nrc = self.make_nrc(nrc) + self.assertEqual(nrc.hosts['foo.domain.com'], ('bar', None, passwd)) + self.assertEqual(nrc.hosts['bar.domain.com'], ('foo', None, 'pass')) + + def test_comment_before_machine_line(self): + self._test_comment("""\ + # comment + machine foo.domain.com login bar password pass + machine bar.domain.com login foo password pass + """) + + def test_comment_before_machine_line_no_space(self): + self._test_comment("""\ + #comment + machine foo.domain.com login bar password pass + machine bar.domain.com login foo password pass + """) + + def test_comment_before_machine_line_hash_only(self): + self._test_comment("""\ + # + machine foo.domain.com login bar password pass + machine bar.domain.com login foo password pass + """) + + def test_comment_at_end_of_machine_line(self): + self._test_comment("""\ + machine foo.domain.com login bar password pass # comment + machine bar.domain.com login foo password pass + """) + + def test_comment_at_end_of_machine_line_no_space(self): + self._test_comment("""\ + machine foo.domain.com login bar password pass #comment + machine bar.domain.com login foo password pass + """) + + def test_comment_at_end_of_machine_line_pass_has_hash(self): + self._test_comment("""\ + machine foo.domain.com login bar password #pass #comment + machine bar.domain.com login foo password pass + """, '#pass') - def test_parses_passwords_with_hash_character(self): - self.assertEqual(self.nrc.hosts['bar'], ('log1', 'acct1', 'pass#')) def test_main(): support.run_unittest(NetrcTestCase) diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 884529f..dd92044 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -278,6 +278,21 @@ class DebuggingServerTests(unittest.TestCase): mexpect = '%s%s\n%s' % (MSG_BEGIN, m.decode('ascii'), MSG_END) self.assertEqual(self.output.getvalue(), mexpect) + def testSendNeedingDotQuote(self): + # Issue 12283 + m = '.A test\n.mes.sage.' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.sendmail('John', 'Sally', m) + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + mexpect = '%s%s\n%s' % (MSG_BEGIN, m, MSG_END) + self.assertEqual(self.output.getvalue(), mexpect) + def testSendMessage(self): m = email.mime.text.MIMEText('A test message') smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index 90aab86..782020c 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -351,6 +351,24 @@ class TestsWithSourceFile(unittest.TestCase): with zipfile.ZipFile(f, "r") as zipfp: self.assertEqual(zipfp.namelist(), [TESTFN]) + def test_ignores_newline_at_end(self): + with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: + zipfp.write(TESTFN, TESTFN) + with open(TESTFN2, 'a') as f: + f.write("\r\n\00\00\00") + with zipfile.ZipFile(TESTFN2, "r") as zipfp: + self.assertIsInstance(zipfp, zipfile.ZipFile) + + def test_ignores_stuff_appended_past_comments(self): + with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: + zipfp.comment = b"this is a comment" + zipfp.write(TESTFN, TESTFN) + with open(TESTFN2, 'a') as f: + f.write("abcdef\r\n") + with zipfile.ZipFile(TESTFN2, "r") as zipfp: + self.assertIsInstance(zipfp, zipfile.ZipFile) + self.assertEqual(zipfp.comment, b"this is a comment") + def test_write_default_name(self): """Check that calling ZipFile.write without arcname specified produces the expected result.""" diff --git a/Lib/zipfile.py b/Lib/zipfile.py index 50f4848..5cc7816 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -246,16 +246,14 @@ def _EndRecData(fpin): # found the magic number; attempt to unpack and interpret recData = data[start:start+sizeEndCentDir] endrec = list(struct.unpack(structEndArchive, recData)) - comment = data[start+sizeEndCentDir:] - # check that comment length is correct - if endrec[_ECD_COMMENT_SIZE] == len(comment): - # Append the archive comment and start offset - endrec.append(comment) - endrec.append(maxCommentStart + start) - - # Try to read the "Zip64 end of central directory" structure - return _EndRecData64(fpin, maxCommentStart + start - filesize, - endrec) + commentSize = endrec[_ECD_COMMENT_SIZE] #as claimed by the zip file + comment = data[start+sizeEndCentDir:start+sizeEndCentDir+commentSize] + endrec.append(comment) + endrec.append(maxCommentStart + start) + + # Try to read the "Zip64 end of central directory" structure + return _EndRecData64(fpin, maxCommentStart + start - filesize, + endrec) # Unable to find a valid end of central directory structure return @@ -609,6 +609,7 @@ Derek Morr James A Morrison Pablo Mouzo Mher Movsisyan +Ruslan Mstoi Sjoerd Mullender Sape Mullender Michael Muller @@ -25,6 +25,21 @@ Core and Builtins Library ------- +- Issue #9284: Allow inspect.findsource() to find the source of doctest + functions. + +- Issue #12009: Fixed regression in netrc file comment handling. + +- Issue #10694: zipfile now ignores garbage at the end of a zipfile. + +- Issue #12283: Fixed regression in smtplib quoting of leading dots in DATA. + +- Issue #12168: SysLogHandler now allows NUL termination to be controlled using + a new 'append_nul' attribute on the handler. + +- Issue #11583: Speed up os.path.isdir on Windows by using GetFileAttributes + instead of os.stat. + - Named tuples now work correctly with vars(). - Issue #12085: Fix an attribute error in subprocess.Popen destructor if the diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 674eeb2..b6f49b8 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2866,6 +2866,45 @@ posix__getfileinformation(PyObject *self, PyObject *args) info.nFileIndexHigh, info.nFileIndexLow); } + +PyDoc_STRVAR(posix__isdir__doc__, +"Return true if the pathname refers to an existing directory."); + +static PyObject * +posix__isdir(PyObject *self, PyObject *args) +{ + PyObject *opath; + char *path; + PyUnicodeObject *po; + DWORD attributes; + + if (PyArg_ParseTuple(args, "U|:_isdir", &po)) { + Py_UNICODE *wpath = PyUnicode_AS_UNICODE(po); + + attributes = GetFileAttributesW(wpath); + if (attributes == INVALID_FILE_ATTRIBUTES) + Py_RETURN_FALSE; + goto check; + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + + if (!PyArg_ParseTuple(args, "O&:_isdir", + PyUnicode_FSConverter, &opath)) + return NULL; + + path = PyBytes_AsString(opath); + attributes = GetFileAttributesA(path); + if (attributes == INVALID_FILE_ATTRIBUTES) + Py_RETURN_FALSE; + +check: + if (attributes & FILE_ATTRIBUTE_DIRECTORY) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} #endif /* MS_WINDOWS */ PyDoc_STRVAR(posix_mkdir__doc__, @@ -8102,6 +8141,7 @@ static PyMethodDef posix_methods[] = { {"_getfullpathname", posix__getfullpathname, METH_VARARGS, NULL}, {"_getfinalpathname", posix__getfinalpathname, METH_VARARGS, NULL}, {"_getfileinformation", posix__getfileinformation, METH_VARARGS, NULL}, + {"_isdir", posix__isdir, METH_VARARGS, posix__isdir__doc__}, #endif #ifdef HAVE_GETLOADAVG {"getloadavg", posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__}, |