Skip to content

Commit 829e419

Browse files
committed
Ensure we always respect --site-packages
- Sometimes we fail to respect `--site-packages` when it is passed with `--install` - This resolves that and ensures we always pass it to `ensure_project` - Fixes #3718 Signed-off-by: Dan Ryan <[email protected]>
1 parent d618cad commit 829e419

File tree

4 files changed

+57
-10
lines changed

4 files changed

+57
-10
lines changed

news/3718.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed a bug which sometimes caused pipenv to fail to respect the ``--site-packages`` flag when passed with ``pipenv install``.

pipenv/cli/command.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
general_options, install_options, lock_options, pass_state,
1919
pypi_mirror_option, python_option, requirementstxt_option,
2020
skip_lock_option, sync_options, system_option, three_option,
21-
uninstall_options, verbose_option
21+
uninstall_options, verbose_option, site_packages_option
2222
)
2323

2424

@@ -217,6 +217,7 @@ def cli(
217217
@system_option
218218
@code_option
219219
@deploy_option
220+
@site_packages_option
220221
@skip_lock_option
221222
@install_options
222223
@pass_state
@@ -249,6 +250,7 @@ def install(
249250
extra_index_url=state.extra_index_urls,
250251
packages=state.installstate.packages,
251252
editable_packages=state.installstate.editables,
253+
site_packages=state.site_packages
252254
)
253255
if retcode:
254256
ctx.abort()
@@ -310,11 +312,10 @@ def lock(
310312
):
311313
"""Generates Pipfile.lock."""
312314
from ..core import ensure_project, do_init, do_lock
313-
314315
# Ensure that virtualenv is available.
315316
ensure_project(
316317
three=state.three, python=state.python, pypi_mirror=state.pypi_mirror,
317-
warn=(not state.quiet)
318+
warn=(not state.quiet), site_packages=state.site_packages, clear=state.clear
318319
)
319320
if state.installstate.requirementstxt:
320321
do_init(
@@ -475,8 +476,10 @@ def update(
475476
do_sync,
476477
project,
477478
)
478-
479-
ensure_project(three=state.three, python=state.python, warn=True, pypi_mirror=state.pypi_mirror)
479+
ensure_project(
480+
three=state.three, python=state.python, pypi_mirror=state.pypi_mirror,
481+
warn=(not state.quiet), site_packages=state.site_packages, clear=state.clear
482+
)
480483
if not outdated:
481484
outdated = bool(dry_run)
482485
if outdated:
@@ -505,12 +508,13 @@ def update(
505508
err=True,
506509
)
507510
ctx.abort()
508-
509511
do_lock(
512+
ctx=ctx,
510513
clear=state.clear,
511514
pre=state.installstate.pre,
512515
keep_outdated=state.installstate.keep_outdated,
513516
pypi_mirror=state.pypi_mirror,
517+
write=not state.quiet,
514518
)
515519
do_sync(
516520
ctx=ctx,

pipenv/core.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,6 +1861,7 @@ def do_install(
18611861
deploy=False,
18621862
keep_outdated=False,
18631863
selective_upgrade=False,
1864+
site_packages=False,
18641865
):
18651866
from .environments import PIPENV_VIRTUALENV, PIPENV_USE_SYSTEM
18661867
from .vendor.pip_shims.shims import PipError
@@ -1888,6 +1889,7 @@ def do_install(
18881889
deploy=deploy,
18891890
skip_requirements=skip_requirements,
18901891
pypi_mirror=pypi_mirror,
1892+
site_packages=site_packages,
18911893
)
18921894
# Don't attempt to install develop and default packages if Pipfile is missing
18931895
if not project.pipfile_exists and not (package_args or dev) and not code:

pipenv/vendor/requirementslib/models/setup_info.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ def make_base_requirements(reqs):
195195
requirements.add(req)
196196
elif isinstance(req, pkg_resources_requirements.Requirement):
197197
requirements.add(BaseRequirement.from_req(req))
198-
elif req and not req.startswith("#"):
198+
elif req and isinstance(req, six.string_types) and not req.startswith("#"):
199199
requirements.add(BaseRequirement.from_string(req))
200200
return requirements
201201

@@ -240,10 +240,15 @@ def get_package_dir_from_setupcfg(parser, base_dir=None):
240240
if "package_dir" in setup_py:
241241
package_lookup = setup_py["package_dir"]
242242
if not isinstance(package_lookup, Mapping):
243-
return package_lookup
244-
return package_lookup.get(
243+
package_dir = package_lookup
244+
package_dir = package_lookup.get(
245245
next(iter(list(package_lookup.keys()))), package_dir
246246
)
247+
if not os.path.isabs(package_dir):
248+
if not base_dir:
249+
package_dir = os.path.join(os.path.getcwd(), package_dir)
250+
else:
251+
package_dir = os.path.join(base_dir, package_dir)
247252
return package_dir
248253

249254

@@ -296,7 +301,8 @@ def parse_setup_cfg(setup_cfg_path):
296301
parser = configparser.ConfigParser(default_opts)
297302
parser.read(setup_cfg_path)
298303
results = {}
299-
package_dir = get_package_dir_from_setupcfg(parser, base_dir=os.getcwd())
304+
base_dir = os.path.dirname(os.path.abspath(setup_cfg_path))
305+
package_dir = get_package_dir_from_setupcfg(parser, base_dir=base_dir)
300306
name, version = get_name_and_version_from_setupcfg(parser, package_dir)
301307
results["name"] = name
302308
results["version"] = version
@@ -638,6 +644,8 @@ def __init__(self):
638644
self.functions = []
639645
self.strings = []
640646
self.assignments = {}
647+
self.binOps = []
648+
self.binOps_map = {}
641649
super(Analyzer, self).__init__()
642650

643651
def generic_visit(self, node):
@@ -652,6 +660,17 @@ def generic_visit(self, node):
652660
self.assignments.update(ast_unparse(node, initial_mapping=True))
653661
super(Analyzer, self).generic_visit(node)
654662

663+
def visit_BinOp(self, node):
664+
left = ast_unparse(node.left, initial_mapping=True)
665+
right = ast_unparse(node.right, initial_mapping=True)
666+
node.left = left
667+
node.right = right
668+
self.binOps.append(node)
669+
670+
def unmap_binops(self):
671+
for binop in self.binOps:
672+
self.binOps_map[binop] = ast_unparse(binop, analyzer=self)
673+
655674
def match_assignment_str(self, match):
656675
return next(
657676
iter(k for k in self.assignments if getattr(k, "id", "") == match), None
@@ -678,6 +697,26 @@ def ast_unparse(item, initial_mapping=False, analyzer=None, recurse=True): # no
678697
unparsed = item.s
679698
elif isinstance(item, ast.Subscript):
680699
unparsed = unparse(item.value)
700+
elif isinstance(item, ast.BinOp):
701+
if analyzer and item in analyzer.binOps_map:
702+
unparsed = analyzer.binOps_map[item]
703+
elif isinstance(item.op, ast.Add):
704+
if not initial_mapping:
705+
right_item = unparse(item.right)
706+
left_item = unparse(item.left)
707+
if not all(
708+
isinstance(side, (six.string_types, int, float, list, tuple))
709+
for side in (left_item, right_item)
710+
):
711+
item.left = left_item
712+
item.right = right_item
713+
unparsed = item
714+
else:
715+
unparsed = right_item + left_item
716+
else:
717+
unparsed = item
718+
elif isinstance(item.op, ast.Sub):
719+
unparsed = unparse(item.left) - unparse(item.right)
681720
elif isinstance(item, ast.Name):
682721
if not initial_mapping:
683722
unparsed = item.id
@@ -787,6 +826,7 @@ def ast_parse_setup_py(path):
787826
# type: (S) -> Dict[Any, Any]
788827
ast_analyzer = ast_parse_file(path)
789828
setup = {} # type: Dict[Any, Any]
829+
ast_analyzer.unmap_binops()
790830
for k, v in ast_analyzer.function_map.items():
791831
fn_name = ""
792832
if isinstance(k, ast.Name):

0 commit comments

Comments
 (0)