Skip to content

Commit

Permalink
Ensure build directories are not temporary (#201)
Browse files Browse the repository at this point in the history
Ensure build directories are not temporary
  • Loading branch information
techalchemy authored Jan 7, 2020
2 parents 8723723 + 1089663 commit ad34828
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 23 deletions.
1 change: 1 addition & 0 deletions news/200.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed an issue which caused build directories to be deleted before dependencies could be determined for editable source reqiurements.
1 change: 1 addition & 0 deletions news/202.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed a bug which could cause parsing to fail for ``setup.cfg`` files on python 2.
15 changes: 11 additions & 4 deletions src/requirementslib/models/requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
make_install_requirement,
normalize_name,
parse_extras,
read_source,
specs_to_string,
split_markers_from_line,
split_ref_from_uri,
Expand Down Expand Up @@ -862,10 +863,16 @@ def metadata(self):
@cached_property
def parsed_setup_cfg(self):
# type: () -> Dict[Any, Any]
if self.is_local and self.path and is_installable_dir(self.path):
if self.setup_cfg:
return parse_setup_cfg(self.setup_cfg)
return {}
if not (
self.is_local
and self.path
and is_installable_dir(self.path)
and self.setup_cfg
):
return {}
base_dir = os.path.dirname(os.path.abspath(self.setup_cfg))
setup_content = read_source(self.setup_cfg)
return parse_setup_cfg(setup_content, base_dir)

@cached_property
def parsed_setup_py(self):
Expand Down
38 changes: 22 additions & 16 deletions src/requirementslib/models/setup_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import atexit
import contextlib
import importlib
import io
import os
import shutil
import sys
Expand Down Expand Up @@ -280,14 +281,8 @@ def get_extras_from_setupcfg(parser):
return extras


def parse_setup_cfg(setup_cfg_path):
# type: (S) -> Dict[S, Union[S, None, Set[BaseRequirement], List[S], Dict[STRING_TYPE, Tuple[BaseRequirement]]]]
if not os.path.exists(setup_cfg_path):
raise FileNotFoundError(setup_cfg_path)
try:
return setuptools_parse_setup_cfg(setup_cfg_path)
except Exception:
pass
def parse_setup_cfg(setup_cfg_contents, base_dir):
# type: (S, S) -> Dict[S, Union[S, None, Set[BaseRequirement], List[S], Dict[STRING_TYPE, Tuple[BaseRequirement]]]]
default_opts = {
"metadata": {"name": "", "version": ""},
"options": {
Expand All @@ -300,9 +295,12 @@ def parse_setup_cfg(setup_cfg_path):
},
}
parser = configparser.ConfigParser(default_opts)
parser.read(setup_cfg_path)
if six.PY2:
buff = io.BytesIO(setup_cfg_contents)
parser.readfp(buff)
else:
parser.read_string(setup_cfg_contents)
results = {}
base_dir = os.path.dirname(os.path.abspath(setup_cfg_path))
package_dir = get_package_dir_from_setupcfg(parser, base_dir=base_dir)
name, version = get_name_and_version_from_setupcfg(parser, package_dir)
results["name"] = name
Expand Down Expand Up @@ -1031,11 +1029,6 @@ def version(self):
self._version = info.get("version", None)
return self._version

@classmethod
def get_setup_cfg(cls, setup_cfg_path):
# type: (S) -> Dict[S, Union[S, None, Set[BaseRequirement], List[S], Tuple[S, Tuple[BaseRequirement]]]]
return parse_setup_cfg(setup_cfg_path)

@property
def egg_base(self):
# type: () -> S
Expand Down Expand Up @@ -1118,7 +1111,14 @@ def get_extras_from_ireq(self):
def parse_setup_cfg(self):
# type: () -> Dict[STRING_TYPE, Any]
if self.setup_cfg is not None and self.setup_cfg.exists():
parsed = self.get_setup_cfg(self.setup_cfg.as_posix())
contents = self.setup_cfg.read_text()
base_dir = self.setup_cfg.absolute().parent.as_posix()
try:
parsed = setuptools_parse_setup_cfg(self.setup_cfg.as_posix())
except Exception:
if six.PY2:
contents = self.setup_cfg.read_bytes()
parsed = parse_setup_cfg(contents, base_dir)
if not parsed:
return {}
return parsed
Expand Down Expand Up @@ -1481,6 +1481,12 @@ def from_ireq(cls, ireq, subdir=None, finder=None, session=None):
raise RequirementError(
"The file URL points to a directory not installable: {}".format(ireq.link)
)
# this ensures the build dir is treated as the temporary build location
# and the source dir is treated as permanent / not deleted by pip
build_location_func = getattr(ireq, "build_location", None)
if build_location_func is None:
build_location_func = getattr(ireq, "ensure_build_location", None)
build_location_func(kwargs["build_dir"])
ireq.ensure_has_source_dir(kwargs["src_dir"])
src_dir = ireq.source_dir

Expand Down
9 changes: 6 additions & 3 deletions tests/unit/test_setup_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,11 @@ def test_ast_parser_finds_fully_qualified_setup(setup_py_dir):


def test_setup_cfg_parser(setup_cfg_dir):
result = parse_setup_cfg(
(setup_cfg_dir / "package_with_multiple_extras/setup.cfg").as_posix()
)
setup_path = setup_cfg_dir / "package_with_multiple_extras/setup.cfg"
if six.PY2:
contents = setup_path.read_bytes()
else:
contents = setup_path.read_text()
result = parse_setup_cfg(contents, setup_path.parent.as_posix())
assert result["version"] == "0.5.0"
assert result["name"] == "test_package"

0 comments on commit ad34828

Please sign in to comment.