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
2 changes: 1 addition & 1 deletion Doc/c-api/complex.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ rather than dereferencing them through pointers.

Please note, that these functions are :term:`soft deprecated` since Python
3.15. Avoid using this API in a new code to do complex arithmetic: either use
the `Number Protocol <number>`_ API or use native complex types, like
the :ref:`Number Protocol <number>` API or use native complex types, like
:c:expr:`double complex`.


Expand Down
2 changes: 1 addition & 1 deletion Doc/extending/first-extension-module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ Then, create ``meson.build`` containing the following:

.. note::

See `meson-python documentation <meson-python>`_ for details on
See the `meson-python documentation <meson-python_>`_ for details on
configuration.

Now, build install the *project in the current directory* (``.``) via ``pip``:
Expand Down
20 changes: 19 additions & 1 deletion Doc/library/shlex.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,15 @@ The :mod:`!shlex` module defines the following functions:
.. versionadded:: 3.8


.. function:: quote(s)
.. function:: quote(s, *, force=False)

Return a shell-escaped version of the string *s*. The returned value is a
string that can safely be used as one token in a shell command line, for
cases where you cannot use a list.

If *force* is :const:`True`, then *s* is unconditionally quoted,
even if it is already safe for a shell without being quoted.

.. _shlex-quote-warning:

.. warning::
Expand Down Expand Up @@ -91,8 +94,23 @@ The :mod:`!shlex` module defines the following functions:
>>> command
['ls', '-l', 'somefile; rm -rf ~']

The *force* keyword can be used to produce consistent behavior when
escaping multiple strings:

>>> from shlex import quote
>>> filenames = ['my first file', 'file2', 'file 3']
>>> filenames_some_escaped = [quote(f) for f in filenames]
>>> filenames_some_escaped
["'my first file'", 'file2', "'file 3'"]
>>> filenames_all_escaped = [quote(f, force=True) for f in filenames]
>>> filenames_all_escaped
["'my first file'", "'file2'", "'file 3'"]

.. versionadded:: 3.3

.. versionchanged:: next
The *force* keyword was added.

The :mod:`!shlex` module defines the following class:


Expand Down
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ os
process via a pidfd. Available on Linux 5.6+.
(Contributed by Maurycy Pawłowski-Wieroński in :gh:`149464`.)

shlex
-----

* Add keyword-only parameter *force* to :func:`shlex.quote` to force quoting
a string, even if it is already safe for a shell without being quoted.
(Contributed by Jay Berry in :gh:`148846`.)

xml
---

Expand Down
14 changes: 10 additions & 4 deletions Lib/shlex.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,12 @@ def join(split_command):
return ' '.join(quote(arg) for arg in split_command)


def quote(s):
"""Return a shell-escaped version of the string *s*."""
def quote(s, *, force=False):
"""Return a shell-escaped version of the string *s*.

If *force* is *True*, then *s* is unconditionally quoted,
even if it is already safe for a shell without being quoted.
"""
if not s:
return "''"

Expand All @@ -329,8 +333,10 @@ def quote(s):
safe_chars = (b'%+,-./0123456789:=@'
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'
b'abcdefghijklmnopqrstuvwxyz')
# No quoting is needed if `s` is an ASCII string consisting only of `safe_chars`
if s.isascii() and not s.encode().translate(None, delete=safe_chars):
# No quoting is needed if we are not forcing quoting
# and `s` is an ASCII string consisting only of `safe_chars`.
if (not force
and s.isascii() and not s.encode().translate(None, delete=safe_chars)):
return s

# use single quotes, and put single quotes into double quotes
Expand Down
26 changes: 25 additions & 1 deletion Lib/test/test_ast/test_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ def test_invalid_identifier(self):
ast.fix_missing_locations(m)
with self.assertRaises(TypeError) as cm:
compile(m, "<test>", "exec")
self.assertIn("identifier must be of type str", str(cm.exception))
self.assertIn("expecting a string object", str(cm.exception))

def test_invalid_constant(self):
for invalid_constant in int, (1, 2, int), frozenset((1, 2, int)):
Expand Down Expand Up @@ -1081,6 +1081,30 @@ def test_none_checks(self) -> None:
for node, attr, source in tests:
self.assert_none_check(node, attr, source)

def test_required_field_messages(self):
binop = ast.BinOp(
left=ast.Constant(value=2),
right=ast.Constant(value=2),
op=ast.Add(),
)
expr_without_position = ast.Expression(body=binop)
expr_with_wrong_body = ast.Expression(body=[binop])

with self.assertRaisesRegex(TypeError, "required field") as cm:
compile(expr_without_position, "<test>", "eval")
with self.assertRaisesRegex(
TypeError,
"field 'body' was expecting node of type 'expr', got 'list'",
):
compile(expr_with_wrong_body, "<test>", "eval")

constant = ast.parse("u'test'", mode="eval")
constant.body.kind = 0xFF
with self.assertRaisesRegex(
TypeError, "field 'kind' was expecting a string or bytes object"
):
compile(constant, "<test>", "eval")

def test_repr(self) -> None:
snapshots = AST_REPR_DATA_FILE.read_text().split("\n")
for test, snapshot in zip(ast_repr_get_test_cases(), snapshots, strict=True):
Expand Down
8 changes: 8 additions & 0 deletions Lib/test/test_shlex.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,14 @@ def testQuote(self):
self.assertRaises(TypeError, shlex.quote, 42)
self.assertRaises(TypeError, shlex.quote, b"abc")

def testForceQuote(self):
self.assertEqual(shlex.quote("spam"), "spam")
self.assertEqual(shlex.quote("spam", force=False), "spam")
self.assertEqual(shlex.quote("spam", force=True), "'spam'")
self.assertEqual(shlex.quote("spam eggs", force=False), "'spam eggs'")
self.assertEqual(shlex.quote("spam eggs", force=True), "'spam eggs'")
self.assertEqual(shlex.quote("two's-complement", force=False), "'two'\"'\"'s-complement'")

def testJoin(self):
for split_command, command in [
(['a ', 'b'], "'a ' b"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Produce more meaningful messages when compiling AST objects with wrong field
values. Patch by Batuhan Taskaya.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add keyword-only parameter *force* to :func:`shlex.quote` to force quoting
a string, even if it is already safe for a shell without being quoted.
80 changes: 47 additions & 33 deletions Misc/python.man
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH PYTHON "1"
.TH PYTHON 1

.\" To view this file while editing, run it through groff:
.\" groff -Tascii -man python.man | less
Expand Down Expand Up @@ -162,7 +162,7 @@ compilation options).
Ignore environment variables like PYTHONPATH and PYTHONHOME that modify
the behavior of the interpreter.
.TP
.B \-h ", " \-? ", "\-\-help
.BR \-h ", " \-? ", " \-\-help
Prints the usage for the interpreter executable and exits.
.TP
.B "\-\-help\-env"
Expand All @@ -171,7 +171,6 @@ Prints help about Python-specific environment variables and exits.
.B "\-\-help\-xoptions"
Prints help about implementation-specific \fB\-X\fP options and exits.
.TP
.TP
.B "\-\-help\-all"
Prints complete usage information and exits.
.TP
Expand Down Expand Up @@ -243,7 +242,7 @@ twice, print a message for each file that is checked for when
searching for a module. Also provides information on module cleanup
at exit.
.TP
.B \-V ", " \-\-version
.BR \-V ", " \-\-version
Prints the Python version number of the executable and exits. When given
twice, print more information about the build.

Expand All @@ -255,23 +254,38 @@ to

The simplest settings apply a particular action unconditionally to all warnings
emitted by a process (even those that are otherwise ignored by default):

-Wdefault # Warn once per call location
-Werror # Convert to exceptions
-Walways # Warn every time
-Wall # Same as -Walways
-Wmodule # Warn once per calling module
-Wonce # Warn once per Python process
-Wignore # Never warn

.RS
.TP
.B \-Wdefault
Warn once per call location
.TP
.B \-Werror
Convert to exceptions
.TP
.B \-Walways
Warn every time
.TP
.B \-Wall
Same as \-Walways
.TP
.B \-Wmodule
Warn once per calling module
.TP
.B \-Wonce
Warn once per Python process
.TP
.B \-Wignore
Never warn
.RE
.IP
The action names can be abbreviated as desired and the interpreter will resolve
them to the appropriate action name. For example,
.B \-Wi
is the same as
.B \-Wignore .
.BR \-Wignore .

The full form of argument is:
.IB action:message:category:module:lineno
.IB action : message : category : module : lineno

Empty fields match all values; trailing empty fields may be omitted. For
example
Expand Down Expand Up @@ -457,7 +471,7 @@ is an empty string; if
is used,
.I sys.argv[0]
contains the string
.I '\-c'.
.RI ' \-c '.
Note that options interpreted by the Python interpreter itself
are not placed in
.IR sys.argv .
Expand Down Expand Up @@ -531,12 +545,12 @@ the \fB\-d\fP option. If set to an integer, it is equivalent to
specifying \fB\-d\fP multiple times.
.IP PYTHONEXECUTABLE
If this environment variable is set,
.IB sys.argv[0]
.I sys.argv[0]
will be set to its value instead of the value got through the C runtime. Only
works on Mac OS X.
.IP PYTHONFAULTHANDLER
If this environment variable is set to a non-empty string,
.IR faulthandler.enable()
.I faulthandler.enable()
is called at startup: install a handler for SIGSEGV, SIGFPE, SIGABRT, SIGBUS
and SIGILL signals to dump the Python traceback.
.IP
Expand Down Expand Up @@ -584,8 +598,8 @@ purpose is to allow repeatable hashing, such as for selftests for the
interpreter itself, or to allow a cluster of python processes to share hash
values.

The integer must be a decimal number in the range [0,4294967295]. Specifying
the value 0 will disable hash randomization.
The integer must be a decimal number in the range [0,4\|294\|967\|295].
Specifying the value 0 will disable hash randomization.
.IP PYTHONHOME
Change the location of the standard Python libraries. By default, the
libraries are searched in ${prefix}/lib/python<version> and
Expand All @@ -607,16 +621,16 @@ This is equivalent to the \fB\-X int_max_str_digits=\fINUMBER\fR option.
.IP PYTHONIOENCODING
If this is set before running the interpreter, it overrides the encoding used
for stdin/stdout/stderr, in the syntax
.IB encodingname ":" errorhandler
.IB encodingname : errorhandler
The
.IB errorhandler
.I errorhandler
part is optional and has the same meaning as in str.encode. For stderr, the
.IB errorhandler
.I errorhandler
part is ignored; the handler will always be \'backslashreplace\'.
.IP PYTHONMALLOC
Set the Python memory allocators and/or install debug hooks. The available
memory allocators are
.IR malloc
.I malloc
and
.IR pymalloc .
The available debug hooks are
Expand All @@ -626,7 +640,7 @@ and
.IR pymalloc_debug .
.IP
When Python is compiled in debug mode, the default is
.IR pymalloc_debug
.I pymalloc_debug
and the debug hooks are automatically used. Otherwise, the default is
.IR pymalloc .
.IP PYTHONMALLOCSTATS
Expand Down Expand Up @@ -707,14 +721,14 @@ Python memory allocations using the tracemalloc module.
.IP
The value of the variable is the maximum number of frames stored in a
traceback of a trace. For example,
.IB PYTHONTRACEMALLOC=1
.I PYTHONTRACEMALLOC=1
stores only the most recent frame.
.IP PYTHONUNBUFFERED
If this is set to a non-empty string it is equivalent to specifying
the \fB\-u\fP option.
.IP PYTHONUSERBASE
Defines the user base directory, which is used to compute the path of the user
.IR site\-packages
.I site\-packages
directory and installation paths for
.IR "python \-m pip install \-\-user" .
.IP PYTHONUTF8
Expand Down Expand Up @@ -750,17 +764,17 @@ This is equivalent to the \fB\-X presite=\fImodule\fR option.
.SH AUTHOR
The Python Software Foundation: https://www.python.org/psf/
.SH INTERNET RESOURCES
Main website: https://www.python.org/
Main website: https://www.python.org/
.br
Documentation: https://docs.python.org/
Documentation: https://docs.python.org/
.br
Developer resources: https://devguide.python.org/
Developer resources: https://devguide.python.org/
.br
Downloads: https://www.python.org/downloads/
Downloads: https://www.python.org/downloads/
.br
Module repository: https://pypi.org/
Module repository: https://pypi.org/
.br
Newsgroups: comp.lang.python, comp.lang.python.announce
Newsgroups: comp.lang.python, comp.lang.python.announce
.SH LICENSING
Python is distributed under an Open Source license. See the file
"LICENSE" in the Python source distribution for information on terms &
Expand Down
Loading
Loading