Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 5180 tempfiles are leak in tmp #5210

Merged
merged 12 commits into from
Aug 3, 2022
2 changes: 2 additions & 0 deletions news/5210.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Write output from ``subprocess_run`` directly to ``stdout`` instead of creating temporary file.
Remove deprecated ``distutils.sysconfig``, use ``sysconfig``.
61 changes: 16 additions & 45 deletions pipenv/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,36 +342,28 @@ def build_command(
pylib_lines = []
pyinc_lines = []
py_command = (
"import sysconfig, distutils.sysconfig, io, json, sys; paths = {{"
"%s }}; value = u'{{0}}'.format(json.dumps(paths));"
"fh = io.open('{0}', 'w'); fh.write(value); fh.close()"
"import sysconfig, json; paths = {%s};"
"value = u'{0}'.format(json.dumps(paths)); print(value)"
)
distutils_line = "distutils.sysconfig.get_python_{0}(plat_specific={1})"
sysconfig_line = "sysconfig.get_path('{0}')"
if python_lib:
for key, var, val in (("pure", "lib", "0"), ("plat", "lib", "1")):
dist_prefix = f"{key}lib"
# XXX: We need to get 'stdlib' or 'platstdlib'
sys_prefix = "{}stdlib".format("" if key == "pure" else key)
for key in ("purelib", "platlib", "stdlib", "platstdlib"):
pylib_lines.append(
f"u'{dist_prefix}': u'{{{{0}}}}'.format({distutils_line.format(var, val)})"
)
pylib_lines.append(
f"u'{sys_prefix}': u'{{{{0}}}}'.format({sysconfig_line.format(sys_prefix)})"
f"u'{key}': u'{{0}}'.format({sysconfig_line.format(key)})"
)
if python_inc:
for key, var, val in (("include", "inc", "0"), ("platinclude", "inc", "1")):
pylib_lines.append(
f"u'{key}': u'{{{{0}}}}'.format({distutils_line.format(var, val)})"
for key in ("include", "platinclude"):
pyinc_lines.append(
f"u'{key}': u'{{0}}'.format({sysconfig_line.format(key)})"
)
lines = pylib_lines + pyinc_lines
if scripts:
lines.append(
"u'scripts': u'{{0}}'.format(%s)" % sysconfig_line.format("scripts")
"u'scripts': u'{0}'.format(%s)" % sysconfig_line.format("scripts")
)
if py_version:
lines.append(
"u'py_version_short': u'{{0}}'.format(distutils.sysconfig.get_python_version()),"
"u'py_version_short': u'{0}'.format(sysconfig.get_python_version()),"
)
lines_as_str = ",".join(lines)
py_command = py_command % lines_as_str
Expand All @@ -384,18 +376,13 @@ def get_paths(self) -> Optional[Dict[str, str]]:
:return: The python paths for the environment
:rtype: Dict[str, str]
"""
tmpfile = vistir.path.create_tracked_tempfile(suffix=".json")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bonus points for removing usage of vistir 💯

tmpfile.close()
tmpfile_path = make_posix(tmpfile.name)
py_command = self.build_command(
python_lib=True, python_inc=True, scripts=True, py_version=True
)
command = [self.python, "-c", py_command.format(tmpfile_path)]
command = [self.python, "-c", py_command]
c = subprocess_run(command)
if c.returncode == 0:
paths = {}
with open(tmpfile_path, "r", encoding="utf-8") as fh:
paths = json.load(fh)
paths = json.loads(c.stdout)
if "purelib" in paths:
paths["libdir"] = paths["purelib"] = make_posix(paths["purelib"])
for key in (
Expand All @@ -420,17 +407,12 @@ def get_lib_paths(self) -> Dict[str, str]:
:return: The python include path for the environment
:rtype: Dict[str, str]
"""
tmpfile = vistir.path.create_tracked_tempfile(suffix=".json")
tmpfile.close()
tmpfile_path = make_posix(tmpfile.name)
py_command = self.build_command(python_lib=True)
command = [self.python, "-c", py_command.format(tmpfile_path)]
command = [self.python, "-c", py_command]
c = subprocess_run(command)
paths = None
if c.returncode == 0:
paths = {}
with open(tmpfile_path, "r", encoding="utf-8") as fh:
paths = json.load(fh)
paths = json.loads(c.stdout)
if "purelib" in paths:
paths["libdir"] = paths["purelib"] = make_posix(paths["purelib"])
for key in ("platlib", "platstdlib", "stdlib"):
Expand Down Expand Up @@ -476,22 +458,11 @@ def get_include_path(self) -> Optional[Dict[str, str]]:
:return: The python include path for the environment
:rtype: Dict[str, str]
"""
tmpfile = vistir.path.create_tracked_tempfile(suffix=".json")
tmpfile.close()
tmpfile_path = make_posix(tmpfile.name)
py_command = (
"import distutils.sysconfig, io, json, sys; paths = {{u'include': "
"u'{{0}}'.format(distutils.sysconfig.get_python_inc(plat_specific=0)), "
"u'platinclude': u'{{0}}'.format(distutils.sysconfig.get_python_inc("
"plat_specific=1)) }}; value = u'{{0}}'.format(json.dumps(paths));"
"fh = io.open('{0}', 'w'); fh.write(value); fh.close()"
)
command = [self.python, "-c", py_command.format(tmpfile_path)]
py_command = self.build_command(python_inc=True)
command = [self.python, "-c", py_command]
c = subprocess_run(command)
if c.returncode == 0:
paths = []
with open(tmpfile_path, "r", encoding="utf-8") as fh:
paths = json.load(fh)
paths = json.loads(c.stdout)
for key in ("include", "platinclude"):
if key in paths:
paths[key] = make_posix(paths[key])
Expand Down