diff --git a/asv_bench/benchmarks/package.py b/asv_bench/benchmarks/package.py index 257c82cba8878..4f97738c81ca3 100644 --- a/asv_bench/benchmarks/package.py +++ b/asv_bench/benchmarks/package.py @@ -3,6 +3,7 @@ """ import subprocess import sys +from security import safe_command class TimeImport: @@ -11,7 +12,7 @@ def time_import(self): # measurement of the import time we actually care about, # without the subprocess or interpreter overhead cmd = [sys.executable, "-X", "importtime", "-c", "import pandas as pd"] - p = subprocess.run(cmd, stderr=subprocess.PIPE, check=True) + p = safe_command.run(subprocess.run, cmd, stderr=subprocess.PIPE, check=True) line = p.stderr.splitlines()[-1] field = line.split(b"|")[-2].strip() diff --git a/doc/make.py b/doc/make.py index dfa8ae6c1e34c..c8a57164944a7 100755 --- a/doc/make.py +++ b/doc/make.py @@ -22,6 +22,7 @@ import docutils import docutils.parsers.rst +from security import safe_command DOC_PATH = os.path.dirname(os.path.abspath(__file__)) SOURCE_PATH = os.path.join(DOC_PATH, "source") @@ -147,7 +148,7 @@ def _sphinx_build(self, kind: str): SOURCE_PATH, os.path.join(BUILD_PATH, kind), ] - return subprocess.call(cmd) + return safe_command.run(subprocess.call, cmd) def _open_browser(self, single_doc_html): """ diff --git a/pandas/_version.py b/pandas/_version.py index 5d610b5e1ea7e..ab5a07e043ab4 100644 --- a/pandas/_version.py +++ b/pandas/_version.py @@ -17,6 +17,7 @@ import subprocess import sys from typing import Callable +from security import safe_command def get_keywords(): @@ -87,8 +88,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env= dispcmd = str([command] + args) try: # remember shell=False, so use git.cmd on windows, not just git - process = subprocess.Popen( - [command] + args, + process = safe_command.run(subprocess.Popen, [command] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, diff --git a/pandas/io/clipboard/__init__.py b/pandas/io/clipboard/__init__.py index 6491849925e86..5fe2b35b5cd61 100644 --- a/pandas/io/clipboard/__init__.py +++ b/pandas/io/clipboard/__init__.py @@ -42,6 +42,7 @@ Pyperclip into running them with whatever permissions the Python process has. """ +from security import safe_command __version__ = "1.8.2" @@ -232,14 +233,14 @@ def copy_wl(text, primary=False): args.append("--clear") subprocess.check_call(args, close_fds=True) else: - p = subprocess.Popen(args, stdin=subprocess.PIPE, close_fds=True) + p = safe_command.run(subprocess.Popen, args, stdin=subprocess.PIPE, close_fds=True) p.communicate(input=text.encode(ENCODING)) def paste_wl(primary=False): args = ["wl-paste", "-n"] if primary: args.append(PRIMARY_SELECTION) - p = subprocess.Popen(args, stdout=subprocess.PIPE, close_fds=True) + p = safe_command.run(subprocess.Popen, args, stdout=subprocess.PIPE, close_fds=True) stdout, _stderr = p.communicate() return stdout.decode(ENCODING) diff --git a/pandas/tests/internals/test_managers.py b/pandas/tests/internals/test_managers.py index f40362c299717..55d0766b25104 100644 --- a/pandas/tests/internals/test_managers.py +++ b/pandas/tests/internals/test_managers.py @@ -17,6 +17,7 @@ SingleArrayManager, SingleBlockManager, ) +from security import safe_command def test_dataframe_creation(): @@ -92,8 +93,7 @@ def test_array_manager_depr_env_var(manager): # GH#55043 test_env = os.environ.copy() test_env["PANDAS_DATA_MANAGER"] = manager - response = subprocess.run( - [sys.executable, "-c", "import pandas"], + response = safe_command.run(subprocess.run, [sys.executable, "-c", "import pandas"], capture_output=True, env=test_env, check=True, diff --git a/pandas/tests/io/conftest.py b/pandas/tests/io/conftest.py index ab6cacc4cc860..eba2648a83c37 100644 --- a/pandas/tests/io/conftest.py +++ b/pandas/tests/io/conftest.py @@ -15,6 +15,7 @@ import pandas.io.common as icom from pandas.io.parsers import read_csv +from security import safe_command @pytest.fixture @@ -92,8 +93,7 @@ def s3_base(worker_id, monkeypatch): endpoint_uri = f"http://127.0.0.1:{endpoint_port}/" # pipe to null to avoid logging in terminal - with subprocess.Popen( - shlex.split(f"moto_server s3 -p {endpoint_port}"), + with safe_command.run(subprocess.Popen, shlex.split(f"moto_server s3 -p {endpoint_port}"), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) as proc: diff --git a/pyproject.toml b/pyproject.toml index 1ac471c62ea2e..74b8c44146a09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,8 @@ dependencies = [ "numpy>=1.26.0,<2; python_version>='3.12'", "python-dateutil>=2.8.2", "pytz>=2020.1", - "tzdata>=2022.7" + "tzdata>=2022.7", + "security==1.3.1" ] classifiers = [ 'Development Status :: 5 - Production/Stable', diff --git a/scripts/validate_docstrings.py b/scripts/validate_docstrings.py index 0a6a852bb0f85..a11d74d1b871c 100755 --- a/scripts/validate_docstrings.py +++ b/scripts/validate_docstrings.py @@ -36,6 +36,7 @@ ) import pandas +from security import safe_command # With template backend, matplotlib plots nothing matplotlib.use("template") @@ -227,7 +228,7 @@ def validate_pep8(self): "--ignore=E203,E3,W503,W504,E402,E731", file.name, ] - response = subprocess.run(cmd, capture_output=True, check=False, text=True) + response = safe_command.run(subprocess.run, cmd, capture_output=True, check=False, text=True) stdout = response.stdout stdout = stdout.replace(file.name, "") messages = stdout.strip("\n").splitlines()