Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Doc/tutorial/stdlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ aids for working with large modules like :mod:`os`::
<returns an extensive manual page created from the module's docstrings>

For daily file and directory management tasks, the :mod:`shutil` module provides
a higher level interface that is easier to use::
a higher-level interface that is easier to use::

>>> import shutil
>>> shutil.copyfile('data.db', 'archive.db')
Expand All @@ -63,7 +63,7 @@ wildcard searches::
Command-line arguments
======================

Common utility scripts often need to process command line arguments. These
Common utility scripts often need to process command-line arguments. These
arguments are stored in the :mod:`sys` module's *argv* attribute as a list. For
instance, let's take the following :file:`demo.py` file::

Expand All @@ -77,7 +77,7 @@ line::
['demo.py', 'one', 'two', 'three']

The :mod:`argparse` module provides a more sophisticated mechanism to process
command line arguments. The following script extracts one or more filenames
command-line arguments. The following script extracts one or more filenames
and an optional number of lines to be displayed::

import argparse
Expand Down
8 changes: 8 additions & 0 deletions Lib/test/test_tools/i18n_data/noheader.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#: noheader.py:3
msgid "Foo"
msgstr ""

#: noheader.py:5
msgid "Bar"
msgstr ""

5 changes: 5 additions & 0 deletions Lib/test/test_tools/i18n_data/noheader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from gettext import gettext as _

_('Foo')

_('Bar')
1 change: 1 addition & 0 deletions Lib/test/test_tools/test_i18n.py
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ def extract_from_snapshots():
'custom_keywords.py': ('--keyword=foo', '--keyword=nfoo:1,2',
'--keyword=pfoo:1c,2',
'--keyword=npfoo:1c,2,3', '--keyword=_:1,2'),
'noheader.py': ('--omit-header',),
'multiple_keywords.py': ('--keyword=foo:1c,2,3', '--keyword=foo:1c,2',
'--keyword=foo:1,2',
# repeat a keyword to make sure it is extracted only once
Expand Down
24 changes: 23 additions & 1 deletion Lib/test/test_trace.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os
from pickle import dump
from pickle import dump, load
import sys
from test.support import captured_stdout, requires_resource
from test.support.os_helper import (TESTFN, rmtree, unlink)
Expand Down Expand Up @@ -561,6 +561,28 @@ def f():
self.assertIn('lines cov% module (path)', stdout)
self.assertIn(f'6 100.0% {modulename} ({filename})', stdout)

def test_count_no_report_accumulates_counts(self):
# --no-report must still save the --file counts so they accumulate.
filename = f'{TESTFN}.py'
countsfile = f'{TESTFN}.counts'
with open(filename, 'w', encoding='utf-8') as fd:
self.addCleanup(unlink, filename)
self.addCleanup(unlink, countsfile)
fd.write('for i in range(3):\n pass\n')
argv = ('-m', 'trace', '--count', '--no-report',
'--file', countsfile, filename)
assert_python_ok(*argv, PYTHONIOENCODING='utf-8')
self.assertTrue(os.path.exists(countsfile))
with open(countsfile, 'rb') as fd:
counts = load(fd)[0]
self.assertTrue(counts)
# A second run accumulates into the same file.
assert_python_ok(*argv, PYTHONIOENCODING='utf-8')
with open(countsfile, 'rb') as fd:
accumulated = load(fd)[0]
self.assertEqual(accumulated,
{key: 2 * value for key, value in counts.items()})

def test_run_as_module(self):
assert_python_ok('-m', 'trace', '-l', '--module', 'timeit', '-n', '1')
assert_python_failure('-m', 'trace', '-l', '--module', 'not_a_module_zzz')
Expand Down
7 changes: 6 additions & 1 deletion Lib/trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,11 @@ def write_results(self, show_missing=True, summary=False, coverdir=None, *,
n_lines, n_hits, modulename, filename = sums[m]
print(f"{n_lines:5d} {n_hits/n_lines:.1%} {modulename} ({filename})")

self._save_counts()

def _save_counts(self):
"""Save the accumulated counts to ``self.outfile`` if one was given."""
if self.outfile:
# try and store counts and module info into self.outfile
try:
with open(self.outfile, 'wb') as f:
pickle.dump((self.counts, self.calledfuncs, self.callers),
Expand Down Expand Up @@ -744,6 +747,8 @@ def parse_ignore_dir(s):

if not opts.no_report:
results.write_results(opts.missing, opts.summary, opts.coverdir)
else:
results._save_counts()

if __name__=='__main__':
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix the :mod:`trace` command-line tool not saving the ``--file`` counts
when ``--no-report`` is used, which prevented accumulating counts over
several runs. Patch by tonghuaroot.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix error handling in the :mod:`zoneinfo` accelerator module when a
transition index is ``-1`` or a TZ string's ``__bool__`` raises.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add ``--omit-header`` option to :program:`pygettext`.
9 changes: 7 additions & 2 deletions Modules/_zoneinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,7 @@ load_data(zoneinfo_state *state, PyZoneInfo_ZoneInfo *self, PyObject *file_obj)
}

Py_ssize_t cur_trans_idx = PyLong_AsSsize_t(num);
if (cur_trans_idx == -1) {
if (cur_trans_idx == -1 && PyErr_Occurred()) {
goto error;
}

Expand Down Expand Up @@ -1181,7 +1181,12 @@ load_data(zoneinfo_state *state, PyZoneInfo_ZoneInfo *self, PyObject *file_obj)
self->ttinfo_before = &(self->_ttinfos[0]);
}

if (tz_str != Py_None && PyObject_IsTrue(tz_str)) {
int has_tz_str = PyObject_IsTrue(tz_str);
if (has_tz_str < 0) {
goto error;
}

if (has_tz_str) {
if (parse_tz_str(state, tz_str, &(self->tzrule_after))) {
goto error;
}
Expand Down
22 changes: 18 additions & 4 deletions Tools/i18n/pygettext.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,15 @@
--width=columns
Set width of output to columns.

--omit-header
Do not write header to file.

This is useful for testing purposes because it eliminates a source of
variance for generated .mo files.

Note: Using this option may lead to an error during compilation or other
manipulation if the resulting file is not entirely in ASCII.

-x filename
--exclude-file=filename
Specify a file that contains a list of strings that are not be
Expand Down Expand Up @@ -629,9 +638,11 @@ def _is_string_const(self, node):
def write_pot_file(messages, options, fp):
timestamp = time.strftime('%Y-%m-%d %H:%M%z')
encoding = fp.encoding if fp.encoding else 'UTF-8'
print(pot_header % {'time': timestamp, 'version': __version__,
'charset': encoding,
'encoding': '8bit'}, file=fp)

if not options.omit_header:
print(pot_header % {'time': timestamp, 'version': __version__,
'charset': encoding,
'encoding': '8bit'}, file=fp)

# Sort locations within each message by filename and lineno
sorted_keys = [
Expand Down Expand Up @@ -691,7 +702,7 @@ def main():
['extract-all', 'add-comments=?', 'default-domain=', 'escape',
'help', 'keyword=', 'no-default-keywords',
'add-location', 'no-location', 'output=', 'output-dir=',
'style=', 'verbose', 'version', 'width=', 'exclude-file=',
'style=', 'verbose', 'version', 'width=', 'omit-header', 'exclude-file=',
'docstrings', 'no-docstrings',
])
except getopt.error as msg:
Expand All @@ -712,6 +723,7 @@ class Options:
locationstyle = GNU
verbose = 0
width = 78
omit_header = False
excludefilename = ''
docstrings = 0
nodocstrings = {}
Expand Down Expand Up @@ -764,6 +776,8 @@ class Options:
options.width = int(arg)
except ValueError:
usage(1, f'--width argument must be an integer: {arg}')
elif opt in ('--omit-header',):
options.omit_header = True
elif opt in ('-x', '--exclude-file'):
options.excludefilename = arg
elif opt in ('-X', '--no-docstrings'):
Expand Down
Loading