Skip to content

Commit

Permalink
Merge branch 'main' into complex-constructor-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
serhiy-storchaka authored May 30, 2024
2 parents 54fbfde + e91fc11 commit 8211f2d
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 159 deletions.
78 changes: 0 additions & 78 deletions Doc/faq/library.rst
Original file line number Diff line number Diff line change
Expand Up @@ -541,84 +541,6 @@ Thus, to read *n* bytes from a pipe *p* created with :func:`os.popen`, you need
use ``p.read(n)``.
.. XXX update to use subprocess. See the :ref:`subprocess-replacements` section.
How do I run a subprocess with pipes connected to both input and output?
------------------------------------------------------------------------
Use the :mod:`popen2` module. For example::
import popen2
fromchild, tochild = popen2.popen2("command")
tochild.write("input\n")
tochild.flush()
output = fromchild.readline()
Warning: in general it is unwise to do this because you can easily cause a
deadlock where your process is blocked waiting for output from the child
while the child is blocked waiting for input from you. This can be caused
by the parent expecting the child to output more text than it does or
by data being stuck in stdio buffers due to lack of flushing.
The Python parent can of course explicitly flush the data it sends to the
child before it reads any output, but if the child is a naive C program it
may have been written to never explicitly flush its output, even if it is
interactive, since flushing is normally automatic.
Note that a deadlock is also possible if you use :func:`popen3` to read
stdout and stderr. If one of the two is too large for the internal buffer
(increasing the buffer size does not help) and you ``read()`` the other one
first, there is a deadlock, too.
Note on a bug in popen2: unless your program calls ``wait()`` or
``waitpid()``, finished child processes are never removed, and eventually
calls to popen2 will fail because of a limit on the number of child
processes. Calling :func:`os.waitpid` with the :const:`os.WNOHANG` option can
prevent this; a good place to insert such a call would be before calling
``popen2`` again.
In many cases, all you really need is to run some data through a command and
get the result back. Unless the amount of data is very large, the easiest
way to do this is to write it to a temporary file and run the command with
that temporary file as input. The standard module :mod:`tempfile` exports a
:func:`~tempfile.mktemp` function to generate unique temporary file names. ::
import tempfile
import os
class Popen3:
"""
This is a deadlock-safe version of popen that returns
an object with errorlevel, out (a string) and err (a string).
(capturestderr may not work under windows.)
Example: print(Popen3('grep spam','\n\nhere spam\n\n').out)
"""
def __init__(self,command,input=None,capturestderr=None):
outfile=tempfile.mktemp()
command="( %s ) > %s" % (command,outfile)
if input:
infile=tempfile.mktemp()
open(infile,"w").write(input)
command=command+" <"+infile
if capturestderr:
errfile=tempfile.mktemp()
command=command+" 2>"+errfile
self.errorlevel=os.system(command) >> 8
self.out=open(outfile,"r").read()
os.remove(outfile)
if input:
os.remove(infile)
if capturestderr:
self.err=open(errfile,"r").read()
os.remove(errfile)
Note that many interactive programs (e.g. vi) don't work well with pipes
substituted for standard input and output. You will have to use pseudo ttys
("ptys") instead of pipes. Or you can use a Python interface to Don Libes'
"expect" library. A Python extension that interfaces to expect is called
"expy" and available from https://expectpy.sourceforge.net. A pure Python
solution that works like expect is :pypi:`pexpect`.
How do I access the serial (RS232) port?
----------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions Doc/howto/pyporting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ please see :ref:`cporting-howto`.

The archived python-porting_ mailing list may contain some useful guidance.

Since Python 3.13 the original porting guide was discontinued.
Since Python 3.11 the original porting guide was discontinued.
You can find the old guide in the
`archive <https://docs.python.org/3.12/howto/pyporting.html>`_.
`archive <https://docs.python.org/3.10/howto/pyporting.html>`_.


Third-party guides
Expand Down
70 changes: 2 additions & 68 deletions Doc/library/subprocess.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1443,36 +1443,8 @@ Environment example::



Replacing :func:`os.popen`, :func:`os.popen2`, :func:`os.popen3`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

::

(child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize)
==>
p = Popen(cmd, shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdin, child_stdout) = (p.stdin, p.stdout)

::

(child_stdin,
child_stdout,
child_stderr) = os.popen3(cmd, mode, bufsize)
==>
p = Popen(cmd, shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
(child_stdin,
child_stdout,
child_stderr) = (p.stdin, p.stdout, p.stderr)

::

(child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize)
==>
p = Popen(cmd, shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)
Replacing :func:`os.popen`
^^^^^^^^^^^^^^^^^^^^^^^^^^

Return code handling translates as follows::

Expand All @@ -1489,44 +1461,6 @@ Return code handling translates as follows::
print("There were some errors")


Replacing functions from the :mod:`!popen2` module
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. note::

If the cmd argument to popen2 functions is a string, the command is executed
through /bin/sh. If it is a list, the command is directly executed.

::

(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)
==>
p = Popen("somestring", shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)

::

(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode)
==>
p = Popen(["mycmd", "myarg"], bufsize=bufsize,
stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)

:class:`popen2.Popen3` and :class:`popen2.Popen4` basically work as
:class:`subprocess.Popen`, except that:

* :class:`Popen` raises an exception if the execution fails.

* The *capturestderr* argument is replaced with the *stderr* argument.

* ``stdin=PIPE`` and ``stdout=PIPE`` must be specified.

* popen2 closes all file descriptors by default, but you have to specify
``close_fds=True`` with :class:`Popen` to guarantee this behavior on
all platforms or past Python versions.


Legacy Shell Invocation Functions
---------------------------------

Expand Down
9 changes: 9 additions & 0 deletions Include/cpython/longobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ PyAPI_FUNC(Py_ssize_t) PyUnstable_Long_CompactValue(const PyLongObject* op);
// There are no error cases.
PyAPI_FUNC(int) _PyLong_Sign(PyObject *v);

/* _PyLong_NumBits. Return the number of bits needed to represent the
absolute value of a long. For example, this returns 1 for 1 and -1, 2
for 2 and -2, and 2 for 3 and -3. It returns 0 for 0.
v must not be NULL, and must be a normalized long.
(size_t)-1 is returned and OverflowError set if the true result doesn't
fit in a size_t.
*/
PyAPI_FUNC(size_t) _PyLong_NumBits(PyObject *v);

/* _PyLong_FromByteArray: View the n unsigned bytes as a binary integer in
base 256, and return a Python int with the same numeric value.
If n is 0, the integer is 0. Else:
Expand Down
11 changes: 0 additions & 11 deletions Include/internal/pycore_long.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,6 @@ extern "C" {
# error "_PY_LONG_DEFAULT_MAX_STR_DIGITS smaller than threshold."
#endif

// _PyLong_NumBits. Return the number of bits needed to represent the
// absolute value of a long. For example, this returns 1 for 1 and -1, 2
// for 2 and -2, and 2 for 3 and -3. It returns 0 for 0.
// v must not be NULL, and must be a normalized long.
// (size_t)-1 is returned and OverflowError set if the true result doesn't
// fit in a size_t.
//
// Export for 'math' shared extension.
PyAPI_FUNC(size_t) _PyLong_NumBits(PyObject *v);


/* runtime lifecycle */

extern PyStatus _PyLong_InitTypes(PyInterpreterState *);
Expand Down
12 changes: 12 additions & 0 deletions InternalDocs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

# CPython Internals Documentation

The documentation in this folder is intended for CPython maintainers.
It describes implementation details of CPython, which should not be
assumed to be part of the Python language specification. These details
can change between any two CPython versions and should not be assumed
to hold for other implementations of the Python language.

The core dev team attempts to keep this documentation up to date. If
it is not, please report that through the
[issue tracker](https://github.com/python/cpython/issues).
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Restore the removed ``_PyLong_NumBits()`` function. It is used by the pywin32 project. Patch by Ethan Smith

0 comments on commit 8211f2d

Please sign in to comment.