branch merge?
This commit is contained in:
commit
a87d586fd6
1
.hgtags
1
.hgtags
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
.. _built-in-consts:
|
||||
|
||||
Built-in Constants
|
||||
==================
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -169,6 +169,8 @@ also be ``.pyw``, in that case, the console window that normally appears is
|
|||
suppressed.
|
||||
|
||||
|
||||
.. _tut-source-encoding:
|
||||
|
||||
Source Code Encoding
|
||||
--------------------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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__)
|
||||
|
|
|
@ -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.
|
||||
|
|
12
Lib/netrc.py
12
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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)
|
||||
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)
|
||||
# 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
|
||||
|
|
15
Misc/NEWS
15
Misc/NEWS
|
@ -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
|
||||
|
|
|
@ -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__},
|
||||
|
|
Loading…
Reference in New Issue