Merge branch 'master' into bugfix-439

This commit is contained in:
dnoetzel
2018-06-25 15:16:56 -05:00
committed by GitHub
114 changed files with 933 additions and 553 deletions
+11
View File
@@ -0,0 +1,11 @@
# Defaults people to autocrlf if they dont have it set
* text=auto
# binaries
*.png
*.jpg
*.tar.gz
*.zip
*.whl
*.exe
*.gif
+162 -72
View File
@@ -1,100 +1,190 @@
2018.6.0.dev0 (2018-06-18)
==========================
2018.6.25 (2018-06-25)
======================
Features & Improvements
-----------------------
- Pipenv-created virtualenvs will now be associated with a ``.project`` folder (features can be implemented on top of this later or users may choose to use ``pipenv-pipes`` to take full advantage of this.) `#1861 <https://github.com/pypa/pipenv/issues/1861>`_
- Virtualenv names will now appear in prompts for most Windows users. `#2167 <https://github.com/pypa/pipenv/issues/2167>`_
- Added support for cmder shell paths with spaces. `#2168 <https://github.com/pypa/pipenv/issues/2168>`_
- Added nested JSON output to the ``pipenv graph`` command. `#2199 <https://github.com/pypa/pipenv/issues/2199>`_
- Dropped vendored pip 9 and vendored, patched, and migrated to pip 10.
Updated patched piptools version. `#2255 <https://github.com/pypa/pipenv/issues/2255>`_
- PyPI mirror URLs can now be set to override instances of PyPI urls by passing the ``--pypi-mirror`` argument from the command line or setting the ``PIPENV_PYPI_MIRROR`` environment variable. `#2281 <https://github.com/pypa/pipenv/issues/2281>`_
- Virtualenv activation lines will now avoid being written to some shell history files. `#2287 <https://github.com/pypa/pipenv/issues/2287>`_
- Pipenv will now only search for ``requirements.txt`` files when creating new projects, and during that time only if the user doesn't specify packages to pass in. `#2309 <https://github.com/pypa/pipenv/issues/2309>`_
- Added support for mounted drives via UNC paths. `#2331 <https://github.com/pypa/pipenv/issues/2331>`_
- Added support for Windows Subsystem for Linux bash shell detection. `#2363 <https://github.com/pypa/pipenv/issues/2363>`_
- Pipenv-created virtualenvs will now be associated with a ``.project`` folder
(features can be implemented on top of this later or users may choose to use
``pipenv-pipes`` to take full advantage of this.) `#1861
<https://github.com/pypa/pipenv/issues/1861>`_
- Virtualenv names will now appear in prompts for most Windows users. `#2167
<https://github.com/pypa/pipenv/issues/2167>`_
- Added support for cmder shell paths with spaces. `#2168
<https://github.com/pypa/pipenv/issues/2168>`_
- Added nested JSON output to the ``pipenv graph`` command. `#2199
<https://github.com/pypa/pipenv/issues/2199>`_
- Dropped vendored pip 9 and vendored, patched, and migrated to pip 10. Updated
patched piptools version. `#2255
<https://github.com/pypa/pipenv/issues/2255>`_
- PyPI mirror URLs can now be set to override instances of PyPI urls by passing
the ``--pypi-mirror`` argument from the command line or setting the
``PIPENV_PYPI_MIRROR`` environment variable. `#2281
<https://github.com/pypa/pipenv/issues/2281>`_
- Virtualenv activation lines will now avoid being written to some shell
history files. `#2287 <https://github.com/pypa/pipenv/issues/2287>`_
- Pipenv will now only search for ``requirements.txt`` files when creating new
projects, and during that time only if the user doesn't specify packages to
pass in. `#2309 <https://github.com/pypa/pipenv/issues/2309>`_
- Added support for mounted drives via UNC paths. `#2331
<https://github.com/pypa/pipenv/issues/2331>`_
- Added support for Windows Subsystem for Linux bash shell detection. `#2363
<https://github.com/pypa/pipenv/issues/2363>`_
- Pipenv will now generate hashes much more quickly by resolving them in a
single pass during locking. `#2384
<https://github.com/pypa/pipenv/issues/2384>`_
- ``pipenv run`` will now avoid spawning additional ``COMSPEC`` instances to
run commands in when possible. `#2385
<https://github.com/pypa/pipenv/issues/2385>`_
- Massive internal improvements to requirements parsing codebase, resolver, and
error messaging. `#2388 <https://github.com/pypa/pipenv/issues/2388>`_
- ``pipenv check`` now may take multiple of the additional argument
``--ignore`` which takes a parameter ``cve_id`` for the purpose of ignoring
specific CVEs. `#2408 <https://github.com/pypa/pipenv/issues/2408>`_
Behavior Changes
----------------
- Pipenv will now parse & capitalize ``platform_python_implementation`` markers
.. warning:: This could cause an issue if you have an out of date ``Pipfile``
which lowercases the comparison value (e.g. ``cpython`` instead of
``CPython``). `#2123 <https://github.com/pypa/pipenv/issues/2123>`_
- Pipenv will now only search for ``requirements.txt`` files when creating new
projects, and during that time only if the user doesn't specify packages to
pass in. `#2309 <https://github.com/pypa/pipenv/issues/2309>`_
.. warning::
This could cause an issue if you have an out of date ``Pipfile`` which lowercases the comparison value (e.g. ``cpython`` instead of ``CPython``). `#2123 <https://github.com/pypa/pipenv/issues/2123>`_
- Pipenv will now only search for ``requirements.txt`` files when creating new projects, and during that time only if the user doesn't specify packages to pass in. `#2309 <https://github.com/pypa/pipenv/issues/2309>`_
Bug Fixes
---------
- Massive internal improvements to requirements parsing codebase, resolver, and error messaging. `#1962 <https://github.com/pypa/pipenv/issues/1962>`_,
- Massive internal improvements to requirements parsing codebase, resolver, and
error messaging. `#1962 <https://github.com/pypa/pipenv/issues/1962>`_,
`#2186 <https://github.com/pypa/pipenv/issues/2186>`_,
`#2263 <https://github.com/pypa/pipenv/issues/2263>`_,
`#2312 <https://github.com/pypa/pipenv/issues/2312>`_
- Pipenv will now parse & capitalize ``platform_python_implementation`` markers. `#2123 <https://github.com/pypa/pipenv/issues/2123>`_
- Fixed a bug with parsing and grouping old-style ``setup.py`` extras during resolution `#2142 <https://github.com/pypa/pipenv/issues/2142>`_
- Fixed a bug causing pipenv graph to throw unhelpful exceptions when running against empty or non-existent environments. `#2161 <https://github.com/pypa/pipenv/issues/2161>`_
- Fixed a bug which caused ``--system`` to incorrectly abort when users were in a virtualenv. `#2181 <https://github.com/pypa/pipenv/issues/2181>`_
- Removed vendored ``cacert.pem`` which could cause issues for some users with custom certificate settings. `#2193 <https://github.com/pypa/pipenv/issues/2193>`_
- Fixed a regression which led to direct invocations of ``virtualenv``, rather than calling it by module. `#2198 <https://github.com/pypa/pipenv/issues/2198>`_
- Pipenv will now parse & capitalize ``platform_python_implementation``
markers. `#2123 <https://github.com/pypa/pipenv/issues/2123>`_
- Fixed a bug with parsing and grouping old-style ``setup.py`` extras during
resolution `#2142 <https://github.com/pypa/pipenv/issues/2142>`_
- Fixed a bug causing pipenv graph to throw unhelpful exceptions when running
against empty or non-existent environments. `#2161
<https://github.com/pypa/pipenv/issues/2161>`_
- Fixed a bug which caused ``--system`` to incorrectly abort when users were in
a virtualenv. `#2181 <https://github.com/pypa/pipenv/issues/2181>`_
- Removed vendored ``cacert.pem`` which could cause issues for some users with
custom certificate settings. `#2193
<https://github.com/pypa/pipenv/issues/2193>`_
- Fixed a regression which led to direct invocations of ``virtualenv``, rather
than calling it by module. `#2198
<https://github.com/pypa/pipenv/issues/2198>`_
- Locking will now pin the correct VCS ref during ``pipenv update`` runs.
Running ``pipenv update`` with a new vcs ref specified in the ``Pipfile`` will now properly obtain, resolve, and install the specified dependency at the specified ref. `#2209 <https://github.com/pypa/pipenv/issues/2209>`_
Running ``pipenv update`` with a new vcs ref specified in the ``Pipfile``
will now properly obtain, resolve, and install the specified dependency at
the specified ref. `#2209 <https://github.com/pypa/pipenv/issues/2209>`_
- ``pipenv clean`` will now correctly ignore comments from ``pip freeze`` when
cleaning the environment. `#2262
<https://github.com/pypa/pipenv/issues/2262>`_
- Resolution bugs causing packages for incompatible python versions to be
locked have been fixed. `#2267
<https://github.com/pypa/pipenv/issues/2267>`_
- Fixed a bug causing pipenv graph to fail to display sometimes. `#2268
<https://github.com/pypa/pipenv/issues/2268>`_
- Updated ``requirementslib`` to fix a bug in pipfile parsing affecting
relative path conversions. `#2269
<https://github.com/pypa/pipenv/issues/2269>`_
- Windows executable discovery now leverages ``os.pathext``. `#2298
<https://github.com/pypa/pipenv/issues/2298>`_
- Fixed a bug which caused ``--deploy --system`` to inadvertently create a
virtualenv before failing. `#2301
<https://github.com/pypa/pipenv/issues/2301>`_
- Fixed an issue which led to a failure to unquote special characters in file
and wheel paths. `#2302 <https://github.com/pypa/pipenv/issues/2302>`_
- VCS dependencies are now manually obtained only if they do not match the
requested ref. `#2304 <https://github.com/pypa/pipenv/issues/2304>`_
- Added error handling functionality to properly cope with single-digit
``Requires-Python`` metatdata with no specifiers. `#2377
<https://github.com/pypa/pipenv/issues/2377>`_
- ``pipenv update`` will now always run the resolver and lock before ensuring
your dependencies are in sync with your lockfile. `#2379
<https://github.com/pypa/pipenv/issues/2379>`_
- Resolved a bug in our patched resolvers which could cause nondeterministic
resolution failures in certain conditions. Running ``pipenv install`` with no
arguments in a project with only a ``Pipfile`` will now correctly lock first
for dependency resolution before installing. `#2384
<https://github.com/pypa/pipenv/issues/2384>`_
- Patched ``python-dotenv`` to ensure that environment variables always get
encoded to the filesystem encoding. `#2386
<https://github.com/pypa/pipenv/issues/2386>`_
Improved Documentation
----------------------
- Update documentation wording to clarify Pipenv's overall role in the packaging ecosystem. `#2194 <https://github.com/pypa/pipenv/issues/2194>`_
- ``pipenv clean`` will now correctly ignore comments from ``pip freeze`` when cleaning the environment. `#2262 <https://github.com/pypa/pipenv/issues/2262>`_
- Added contribution documentation and guidelines. `#2205 <https://github.com/pypa/pipenv/issues/2205>`_
- Resolution bugs causing packages for incompatible python versions to be locked have been fixed. `#2267 <https://github.com/pypa/pipenv/issues/2267>`_
- Fixed a bug causing pipenv graph to fail to display sometimes. `#2268 <https://github.com/pypa/pipenv/issues/2268>`_
- Updated ``requirementslib`` to fix a bug in pipfile parsing affecting relative path conversions. `#2269 <https://github.com/pypa/pipenv/issues/2269>`_
- Windows executable discovery now leverages ``os.pathext``. `#2298 <https://github.com/pypa/pipenv/issues/2298>`_
- Fixed a bug which caused ``--deploy --system`` to inadvertently create a virtualenv before failing. `#2301 <https://github.com/pypa/pipenv/issues/2301>`_
- Fixed an issue which led to a failure to unquote special characters in file and wheel paths. `#2302 <https://github.com/pypa/pipenv/issues/2302>`_
- VCS dependencies are now manually obtained only if they do not match the requested ref. `#2304 <https://github.com/pypa/pipenv/issues/2304>`_
- Added error handling functionality to properly cope with single-digit ``Requires-Python`` metatdata with no specifiers. `#2377 <https://github.com/pypa/pipenv/issues/2377>`_
- ``pipenv update`` will now always run the resolver and lock before ensuring your dependencies are in sync with your lockfile. `#2379 <https://github.com/pypa/pipenv/issues/2379>`_
- Added instructions for supervisord compatibility. `#2215 <https://github.com/pypa/pipenv/issues/2215>`_
- Fixed broken links to development philosophy and contribution documentation. `#2248 <https://github.com/pypa/pipenv/issues/2248>`_
Vendored Libraries
------------------
- Removed vendored ``cacert.pem`` which could cause issues for some users with custom certificate settings. `#2193 <https://github.com/pypa/pipenv/issues/2193>`_
- Dropped vendored pip 9 and vendored, patched, and migrated to pip 10.
Updated patched piptools version. `#2255 <https://github.com/pypa/pipenv/issues/2255>`_
- Updated ``requirementslib`` to fix a bug in pipfile parsing affecting relative path conversions. `#2269 <https://github.com/pypa/pipenv/issues/2269>`_
- Added custom shell detection library ``shellingham``, a port of our changes to ``pew``. `#2363 <https://github.com/pypa/pipenv/issues/2363>`_
- Removed vendored ``cacert.pem`` which could cause issues for some users with
custom certificate settings. `#2193
<https://github.com/pypa/pipenv/issues/2193>`_
- Dropped vendored pip 9 and vendored, patched, and migrated to pip 10. Updated
patched piptools version. `#2255
<https://github.com/pypa/pipenv/issues/2255>`_
- Updated ``requirementslib`` to fix a bug in pipfile parsing affecting
relative path conversions. `#2269
<https://github.com/pypa/pipenv/issues/2269>`_
- Added custom shell detection library ``shellingham``, a port of our changes
to ``pew``. `#2363 <https://github.com/pypa/pipenv/issues/2363>`_
- Patched ``python-dotenv`` to ensure that environment variables always get
encoded to the filesystem encoding. `#2386
<https://github.com/pypa/pipenv/issues/2386>`_
- Updated vendored libraries. The following vendored libraries were updated:
* distlib from version ``0.2.6`` to ``0.2.7``.
+7 -1
View File
@@ -1,4 +1,10 @@
- Virtualenv names will now appear in prompts for most Windows users. 2167 feature
2018.6.25
- Added error handling functionality to properly cope with single-digit `Requires-Python` metatdata with no specifiers.
- Pipenv will now generate hashes much more quickly by resolving them in a single pass during locking.
- `pipenv run` will now avoid spawning additional `COMSPEC` instances to run commands in when possible.
- `pipenv check` now may take multiple of the additional argument `--ignore` which takes a parameter `cve_id` for the purpose of ignoring specific CVEs.
- Patched `python-dotenv` to ensure that environment variables always get encoded to the filesystem encoding.
- Virtualenv names will now appear in prompts for most Windows users.
- Resolver runtime and caching has been improved.
- Improved virtualenv discovery when using `pipenv --venv`.
- Improved error messages when failing to activate virtualenvs.
-1
View File
@@ -1 +0,0 @@
Pipenv-created virtualenvs will now be associated with a ``.project`` folder (features can be implemented on top of this later or users may choose to use ``pipenv-pipes`` to take full advantage of this.)
-1
View File
@@ -1 +0,0 @@
Massive internal improvements to requirements parsing codebase, resolver, and error messaging.
-5
View File
@@ -1,5 +0,0 @@
Pipenv will now parse & capitalize ``platform_python_implementation`` markers
.. warning::
This could cause an issue if you have an out of date ``Pipfile`` which lowercases the comparison value (e.g. ``cpython`` instead of ``CPython``).
-1
View File
@@ -1 +0,0 @@
Pipenv will now parse & capitalize ``platform_python_implementation`` markers.
-1
View File
@@ -1 +0,0 @@
Fixed a bug with parsing and grouping old-style ``setup.py`` extras during resolution
-1
View File
@@ -1 +0,0 @@
Fixed a bug causing pipenv graph to throw unhelpful exceptions when running against empty or non-existent environments.
-1
View File
@@ -1 +0,0 @@
Virtualenv names will now appear in prompts for most Windows users.
-1
View File
@@ -1 +0,0 @@
Added support for cmder shell paths with spaces.
-1
View File
@@ -1 +0,0 @@
Fixed a bug which caused ``--system`` to incorrectly abort when users were in a virtualenv.
-1
View File
@@ -1 +0,0 @@
Added an invoke task to generate patches against vendored dependencies.
-1
View File
@@ -1 +0,0 @@
Massive internal improvements to requirements parsing codebase, resolver, and error messaging.
-1
View File
@@ -1 +0,0 @@
Removed vendored ``cacert.pem`` which could cause issues for some users with custom certificate settings.
-1
View File
@@ -1 +0,0 @@
Removed vendored ``cacert.pem`` which could cause issues for some users with custom certificate settings.
-1
View File
@@ -1 +0,0 @@
Update documentation wording to clarify Pipenv's overall role in the packaging ecosystem.
-1
View File
@@ -1 +0,0 @@
Fixed a regression which led to direct invocations of ``virtualenv``, rather than calling it by module.
-1
View File
@@ -1 +0,0 @@
Added nested JSON output to the ``pipenv graph`` command.
-1
View File
@@ -1 +0,0 @@
Added contribution documentation and guidelines.
-2
View File
@@ -1,2 +0,0 @@
Locking will now pin the correct VCS ref during ``pipenv update`` runs.
Running ``pipenv update`` with a new vcs ref specified in the ``Pipfile`` will now properly obtain, resolve, and install the specified dependency at the specified ref.
-1
View File
@@ -1 +0,0 @@
Added instructions for supervisord compatibility.
-1
View File
@@ -1 +0,0 @@
Fixed broken links to development philosophy and contribution documentation.
-2
View File
@@ -1,2 +0,0 @@
Dropped vendored pip 9 and vendored, patched, and migrated to pip 10.
Updated patched piptools version.
-2
View File
@@ -1,2 +0,0 @@
Dropped vendored pip 9 and vendored, patched, and migrated to pip 10.
Updated patched piptools version.
-1
View File
@@ -1 +0,0 @@
``pipenv clean`` will now correctly ignore comments from ``pip freeze`` when cleaning the environment.
-1
View File
@@ -1 +0,0 @@
Massive internal improvements to requirements parsing codebase, resolver, and error messaging.
-1
View File
@@ -1 +0,0 @@
Resolution bugs causing packages for incompatible python versions to be locked have been fixed.
-1
View File
@@ -1 +0,0 @@
Fixed a bug causing pipenv graph to fail to display sometimes.
-1
View File
@@ -1 +0,0 @@
Updated ``requirementslib`` to fix a bug in pipfile parsing affecting relative path conversions.
-1
View File
@@ -1 +0,0 @@
Updated ``requirementslib`` to fix a bug in pipfile parsing affecting relative path conversions.
-1
View File
@@ -1 +0,0 @@
PyPI mirror URLs can now be set to override instances of PyPI urls by passing the ``--pypi-mirror`` argument from the command line or setting the ``PIPENV_PYPI_MIRROR`` environment variable.
-1
View File
@@ -1 +0,0 @@
Virtualenv activation lines will now avoid being written to some shell history files.
-1
View File
@@ -1 +0,0 @@
Windows executable discovery now leverages ``os.pathext``.
-1
View File
@@ -1 +0,0 @@
Fixed a bug which caused ``--deploy --system`` to inadvertently create a virtualenv before failing.
-1
View File
@@ -1 +0,0 @@
Fixed an issue which led to a failure to unquote special characters in file and wheel paths.
-1
View File
@@ -1 +0,0 @@
VCS dependencies are now manually obtained only if they do not match the requested ref.
-1
View File
@@ -1 +0,0 @@
Change function name of ``pipenv.utils.actually_resolve_reps`` to ``pipenv.utils.actually_resolve_deps``.
-1
View File
@@ -1 +0,0 @@
Pipenv will now only search for ``requirements.txt`` files when creating new projects, and during that time only if the user doesn't specify packages to pass in.
-1
View File
@@ -1 +0,0 @@
Pipenv will now only search for ``requirements.txt`` files when creating new projects, and during that time only if the user doesn't specify packages to pass in.
-1
View File
@@ -1 +0,0 @@
Removed unnecessary comma from documentation.
-1
View File
@@ -1 +0,0 @@
Massive internal improvements to requirements parsing codebase, resolver, and error messaging.
-1
View File
@@ -1 +0,0 @@
Added ``pipenv run`` suggestion for users who are first creating environment.
-1
View File
@@ -1 +0,0 @@
Added support for mounted drives via UNC paths.
-1
View File
@@ -1 +0,0 @@
Added support for Windows Subsystem for Linux bash shell detection.
-1
View File
@@ -1 +0,0 @@
Added custom shell detection library ``shellingham``, a port of our changes to ``pew``.
-15
View File
@@ -1,15 +0,0 @@
Updated vendored libraries. The following vendored libraries were updated:
* distlib from version ``0.2.6`` to ``0.2.7``.
* jinja2 from version ``2.9.5`` to ``2.10``.
* pathlib2 from version ``2.1.0`` to ``2.3.2``.
* parse from version ``2.8.0`` to ``2.8.4``.
* pexpect from version ``2.5.2`` to ``2.6.0``.
* requests from version ``2.18.4`` to ``2.19.1``.
* idna from version ``2.6`` to ``2.7``.
* certifi from version ``2018.1.16`` to ``2018.4.16``.
* packaging from version ``16.8`` to ``17.1``.
* six from version ``1.10.0`` to ``1.11.0``.
* requirementslib from version ``0.2.0`` to ``1.0.1``.
In addition, scandir was vendored and patched to avoid importing host system binaries when falling back to pathlib2.
-1
View File
@@ -1 +0,0 @@
Added error handling functionality to properly cope with single-digit ``Requires-Python`` metatdata with no specifiers.
-1
View File
@@ -1 +0,0 @@
``pipenv update`` will now always run the resolver and lock before ensuring your dependencies are in sync with your lockfile.
-1
View File
@@ -1 +0,0 @@
Patched ``python-dotenv`` to ensure that environment variables always get encoded to the filesystem encoding.
-1
View File
@@ -1 +0,0 @@
Patched ``python-dotenv`` to ensure that environment variables always get encoded to the filesystem encoding.
-1
View File
@@ -1 +0,0 @@
Massive internal improvements to requirements parsing codebase, resolver, and error messaging.
-1
View File
@@ -1 +0,0 @@
Added release tasks for maintainers.
+1 -1
View File
@@ -2,4 +2,4 @@
# // ) ) / / // ) ) //___) ) // ) ) || / /
# //___/ / / / //___/ / // // / / || / /
# // / / // ((____ // / / ||/ /
__version__ = '2018.6.0.dev0'
__version__ = '2018.6.25'
+24 -13
View File
@@ -356,16 +356,16 @@ def cli(
'--deploy',
is_flag=True,
default=False,
help=u"Abort if the Pipfile.lock is outofdate, or Python version is wrong.",
help=u"Abort if the Pipfile.lock is out-of-date, or Python version is wrong.",
)
@option(
'--pre', is_flag=True, default=False, help=u"Allow prereleases."
'--pre', is_flag=True, default=False, help=u"Allow pre-releases."
)
@option(
'--keep-outdated',
is_flag=True,
default=False,
help=u"Keep outdated dependencies from being updated in Pipfile.lock.",
help=u"Keep out-dated dependencies from being updated in Pipfile.lock.",
)
@option(
'--selective-upgrade',
@@ -463,7 +463,7 @@ def install(
'--keep-outdated',
is_flag=True,
default=False,
help=u"Keep outdated dependencies from being updated in Pipfile.lock.",
help=u"Keep out-dated dependencies from being updated in Pipfile.lock.",
)
@option(
'--pypi-mirror',
@@ -549,13 +549,13 @@ def uninstall(
'--clear', is_flag=True, default=False, help="Clear the dependency cache."
)
@option(
'--pre', is_flag=True, default=False, help=u"Allow prereleases."
'--pre', is_flag=True, default=False, help=u"Allow pre-releases."
)
@option(
'--keep-outdated',
is_flag=True,
default=False,
help=u"Keep outdated dependencies from being updated in Pipfile.lock.",
help=u"Keep out-dated dependencies from being updated in Pipfile.lock.",
)
def lock(
three=None,
@@ -694,6 +694,12 @@ def run(command, args, three=None, python=False):
default=False,
help="Given a code path, show potentially unused dependencies.",
)
@option(
'--ignore',
'-i',
multiple=True,
help="Ignore specified vulnerability during safety checks."
)
@argument('args', nargs=-1)
def check(
three=None,
@@ -701,12 +707,17 @@ def check(
system=False,
unused=False,
style=False,
ignore=None,
args=None,
):
from .core import do_check
do_check(
three=three, python=python, system=system, unused=unused, args=args
three=three,
python=python,
system=system,
unused=unused,
ignore=ignore,
args=args
)
@@ -752,13 +763,13 @@ def check(
)
@option('--bare', is_flag=True, default=False, help="Minimal output.")
@option(
'--pre', is_flag=True, default=False, help=u"Allow prereleases."
'--pre', is_flag=True, default=False, help=u"Allow pre-releases."
)
@option(
'--keep-outdated',
is_flag=True,
default=False,
help=u"Keep outdated dependencies from being updated in Pipfile.lock.",
help=u"Keep out-dated dependencies from being updated in Pipfile.lock.",
)
@option(
'--sequential',
@@ -770,13 +781,13 @@ def check(
'--outdated',
is_flag=True,
default=False,
help=u"List outofdate dependencies.",
help=u"List out-of-date dependencies.",
)
@option(
'--dry-run',
is_flag=True,
default=None,
help=u"List outofdate dependencies.",
help=u"List out-of-date dependencies.",
)
@argument('package', default=False)
@pass_context
@@ -855,7 +866,7 @@ def update(
@command(
short_help=u"Displays currentlyinstalled dependency graph information."
short_help=u"Displays currently-installed dependency graph information."
)
@option('--bare', is_flag=True, default=False, help="Minimal output.")
@option('--json', is_flag=True, default=False, help="Output JSON.")
+165 -148
View File
@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
# -*- coding=utf-8 -*-
import contextlib
import logging
import os
@@ -47,13 +47,11 @@ from .utils import (
is_star,
rmtree,
split_argument,
extract_uri_from_vcs_dep,
fs_str,
clean_resolved_dep,
)
from ._compat import (
TemporaryDirectory,
vcs,
Path
)
from .import pep508checker, progress
@@ -161,7 +159,7 @@ def load_dot_env():
if os.path.isfile(denv):
click.echo(
crayons.normal(
'Loading .env environment variables', bold=True
'Loading .env environment variables...', bold=True
),
err=True,
)
@@ -280,7 +278,7 @@ def ensure_pipfile(validate=True, skip_requirements=False, system=False):
if project.requirements_exists and not skip_requirements:
click.echo(
crayons.normal(
u'requirements.txt found, instead of Pipfile! Converting',
u'requirements.txt found, instead of Pipfile! Converting...',
bold=True,
)
)
@@ -303,7 +301,7 @@ def ensure_pipfile(validate=True, skip_requirements=False, system=False):
else:
click.echo(
crayons.normal(
u'Creating a Pipfile for this project', bold=True
u'Creating a Pipfile for this project...', bold=True
),
err=True,
)
@@ -317,7 +315,7 @@ def ensure_pipfile(validate=True, skip_requirements=False, system=False):
# Write changes out to disk.
if changed:
click.echo(
crayons.normal(u'Fixing package names in Pipfile', bold=True),
crayons.normal(u'Fixing package names in Pipfile...', bold=True),
err=True,
)
project.write_toml(p)
@@ -414,7 +412,6 @@ def ensure_python(three=None, python=None):
sys.exit(1)
def activate_pyenv():
import notpip
from notpip._vendor.packaging.version import parse as parse_version
"""Adds all pyenv installations to the PATH."""
@@ -463,7 +460,7 @@ def ensure_python(three=None, python=None):
u'{0}: Python {1} {2}'.format(
crayons.red('Warning', bold=True),
crayons.blue(python),
u'was not found on your system',
u'was not found on your system...',
),
err=True,
)
@@ -513,7 +510,7 @@ def ensure_python(three=None, python=None):
),
crayons.normal(u'with pyenv', bold=True),
crayons.normal(u'(this may take a few minutes)'),
crayons.normal(u'', bold=True),
crayons.normal(u'...', bold=True),
)
)
with spinner():
@@ -528,7 +525,7 @@ def ensure_python(three=None, python=None):
try:
assert c.return_code == 0
except AssertionError:
click.echo(u'Something went wrong')
click.echo(u'Something went wrong...')
click.echo(crayons.blue(c.err), err=True)
# Print the results, in a beautiful blue...
click.echo(crayons.blue(c.out), err=True)
@@ -595,7 +592,7 @@ def ensure_virtualenv(three=None, python=None, site_packages=False):
):
abort()
click.echo(
crayons.normal(u'Removing existing virtualenv', bold=True),
crayons.normal(u'Removing existing virtualenv...', bold=True),
err=True,
)
# Remove the virtualenv.
@@ -720,7 +717,7 @@ def do_install_dependencies(
verbose=False,
concurrent=True,
requirements_dir=None,
pypi_mirror = False,
pypi_mirror=False,
):
""""Executes the install functionality.
@@ -755,7 +752,7 @@ def do_install_dependencies(
if not bare:
click.echo(
crayons.normal(
u'Installing dependencies from Pipfile', bold=True
u'Installing dependencies from Pipfile...', bold=True
)
)
lockfile = split_file(project._lockfile)
@@ -765,7 +762,7 @@ def do_install_dependencies(
if not bare:
click.echo(
crayons.normal(
u'Installing dependencies from Pipfile.lock ({0})'.format(
u'Installing dependencies from Pipfile.lock ({0})...'.format(
lockfile['_meta'].get('hash', {}).get('sha256')[-6:]
),
bold=True,
@@ -836,7 +833,7 @@ def do_install_dependencies(
if failed_deps_list:
click.echo(
crayons.normal(
u'Installing initiallyfailed dependencies', bold=True
u'Installing initially failed dependencies...', bold=True
)
)
for dep, ignore_hash in progress.bar(
@@ -891,7 +888,7 @@ def convert_three_to_python(three, python):
def do_create_virtualenv(python=None, site_packages=False):
"""Creates a virtualenv."""
click.echo(
crayons.normal(u'Creating a virtualenv for this project', bold=True),
crayons.normal(u'Creating a virtualenv for this project...', bold=True),
err=True,
)
click.echo(u'Pipfile: {0}'.format(
@@ -925,7 +922,7 @@ def do_create_virtualenv(python=None, site_packages=False):
u'{0} {1} {3} {2}'.format(
crayons.normal('Using', bold=True),
crayons.red(python, bold=True),
crayons.normal(u'to create virtualenv', bold=True),
crayons.normal(u'to create virtualenv...', bold=True),
crayons.green('({0})'.format(python_version(python))),
),
err=True,
@@ -953,7 +950,7 @@ def do_create_virtualenv(python=None, site_packages=False):
# Enable site-packages, if desired...
if not project.is_venv_in_project() and site_packages:
click.echo(
crayons.normal(u'Making site-packages available', bold=True),
crayons.normal(u'Making site-packages available...', bold=True),
err=True,
)
os.environ['VIRTUAL_ENV'] = project.virtualenv_location
@@ -1007,7 +1004,7 @@ def do_lock(
pre=False,
keep_outdated=False,
write=True,
pypi_mirror = None,
pypi_mirror=None,
):
"""Executes the freeze functionality."""
from .utils import get_vcs_deps
@@ -1065,7 +1062,7 @@ def do_lock(
u'{0} {1} {2}'.format(
crayons.normal('Locking'),
crayons.red('[{0}]'.format(settings['log_string'])),
crayons.normal('dependencies…'),
crayons.normal('dependencies...'),
),
err=True,
)
@@ -1133,7 +1130,7 @@ def do_lock(
vcs_lockfile.update(dep_lockfile)
lockfile[settings['lockfile_key']].update(vcs_lockfile)
# Support for --keep-outdated
# Support for --keep-outdated...
if keep_outdated:
for section_name, section in (
('default', project.packages), ('develop', project.dev_packages)
@@ -1198,7 +1195,7 @@ def do_purge(bare=False, downloads=False, allow_global=False, verbose=False):
if downloads:
if not bare:
click.echo(
crayons.normal(u'Clearing out downloads directory', bold=True)
crayons.normal(u'Clearing out downloads directory...', bold=True)
)
shutil.rmtree(project.download_location)
return
@@ -1230,7 +1227,7 @@ def do_purge(bare=False, downloads=False, allow_global=False, verbose=False):
actually_installed.append(dep)
if not bare:
click.echo(
u'Found {0} installed package(s), purging'.format(
u'Found {0} installed package(s), purging...'.format(
len(actually_installed)
)
)
@@ -1262,6 +1259,7 @@ def do_init(
pypi_mirror=None,
):
"""Executes the init functionality."""
cleanup_reqdir = False
global PIPENV_VIRTUALENV
if not system:
if not project.virtualenv_exists:
@@ -1273,6 +1271,7 @@ def do_init(
# Ensure the Pipfile exists.
ensure_pipfile(system=system)
if not requirements_dir:
cleanup_reqdir = True
requirements_dir = TemporaryDirectory(
suffix='-requirements', prefix='pipenv-'
)
@@ -1311,14 +1310,14 @@ def do_init(
else:
click.echo(
crayons.red(
u'Pipfile.lock ({0}) out of date, updating to ({1})'.format(
u'Pipfile.lock ({0}) out of date, updating to ({1})...'.format(
old_hash[-6:], new_hash[-6:]
),
bold=True,
),
err=True,
)
do_lock(system=system, pre=pre, keep_outdated=keep_outdated, pypi_mirror=pypi_mirror)
do_lock(system=system, pre=pre, keep_outdated=keep_outdated, write=True, pypi_mirror=pypi_mirror)
# Write out the lockfile if it doesn't exist.
if not project.lockfile_exists and not skip_lock:
# Unless we're in a virtualenv not managed by pipenv, abort if we're
@@ -1336,7 +1335,7 @@ def do_init(
sys.exit(1)
else:
click.echo(
crayons.normal(u'Pipfile.lock not found, creating', bold=True),
crayons.normal(u'Pipfile.lock not found, creating...', bold=True),
err=True,
)
do_lock(
@@ -1344,6 +1343,7 @@ def do_init(
pre=pre,
keep_outdated=keep_outdated,
verbose=verbose,
write=True,
pypi_mirror=pypi_mirror,
)
do_install_dependencies(
@@ -1356,7 +1356,8 @@ def do_init(
requirements_dir=requirements_dir.name,
pypi_mirror=pypi_mirror,
)
requirements_dir.cleanup()
if cleanup_reqdir:
requirements_dir.cleanup()
# Hint the user what to do to activate the virtualenv.
if not allow_global and not deploy and 'PIPENV_ACTIVE' not in os.environ:
@@ -1383,7 +1384,7 @@ def pip_install(
selective_upgrade=False,
requirements_dir=None,
extra_indexes=None,
pypi_mirror = None,
pypi_mirror=None,
):
from notpip._internal import logger as piplogger
from notpip._vendor.pyparsing import ParseException
@@ -1679,7 +1680,7 @@ def warn_in_virtualenv():
def ensure_lockfile(keep_outdated=False, pypi_mirror=None):
"""Ensures that the lockfile is uptodate."""
"""Ensures that the lockfile is up-to-date."""
if not keep_outdated:
keep_outdated = project.settings.get('keep_outdated')
# Write out the lockfile if it doesn't exist, but not if the Pipfile is being ignored
@@ -1689,7 +1690,7 @@ def ensure_lockfile(keep_outdated=False, pypi_mirror=None):
if new_hash != old_hash:
click.echo(
crayons.red(
u'Pipfile.lock ({0}) out of date, updating to ({1})'.format(
u'Pipfile.lock ({0}) out of date, updating to ({1})...'.format(
old_hash[-6:], new_hash[-6:]
),
bold=True,
@@ -1738,7 +1739,7 @@ def do_outdated(pypi_mirror=None):
)
for package, new_version, old_version in outdated:
click.echo(
'Package {0!r} outofdate: {1!r} installed, {2!r} available.'.format(
'Package {0!r} out-of-date: {1!r} installed, {2!r} available.'.format(
package, old_version, new_version
)
)
@@ -1821,7 +1822,7 @@ def do_install(
# Download requirements file
click.echo(
crayons.normal(
u'Remote requirements file provided! Downloading', bold=True
u'Remote requirements file provided! Downloading...', bold=True
),
err=True,
)
@@ -1845,7 +1846,7 @@ def do_install(
error, traceback = None, None
click.echo(
crayons.normal(
u'Requirements file provided! Importing into Pipfile',
u'Requirements file provided! Importing into Pipfile...',
bold=True,
),
err=True,
@@ -1881,7 +1882,7 @@ def do_install(
if code:
click.echo(
crayons.normal(
u'Discovering imports from local codebase', bold=True
u'Discovering imports from local codebase...', bold=True
)
)
for req in import_from_code(code):
@@ -1929,27 +1930,9 @@ def do_install(
more_packages.extend(converted)
# Allow more than one package to be provided.
package_names = [package_name] + more_packages
# Install all dependencies, if none was provided.
if package_name is False:
# Update project settings with pre preference.
if pre:
project.update_settings({'allow_prereleases': pre})
do_init(
dev=dev,
allow_global=system,
ignore_pipfile=ignore_pipfile,
system=system,
skip_lock=skip_lock,
verbose=verbose,
concurrent=concurrent,
deploy=deploy,
pre=pre,
requirements_dir=requirements_directory,
pypi_mirror=pypi_mirror,
)
requirements_directory.cleanup()
sys.exit(0)
# Support for --selective-upgrade.
# We should do this part first to make sure that we actually do selectively upgrade
# the items specified
if selective_upgrade:
for i, package_name in enumerate(package_names[:]):
section = project.packages if not dev else project.dev_packages
@@ -1969,94 +1952,116 @@ def do_install(
]
except KeyError:
pass
for package_name in package_names:
click.echo(
crayons.normal(
u'Installing {0}'.format(
crayons.green(package_name, bold=True)
),
bold=True,
)
# Install all dependencies, if none was provided.
# This basically ensures that we have a pipfile and lockfile, then it locks and
# installs from the lockfile
if package_name is False:
# Update project settings with pre preference.
if pre:
project.update_settings({'allow_prereleases': pre})
do_init(
dev=dev,
allow_global=system,
ignore_pipfile=ignore_pipfile,
system=system,
skip_lock=skip_lock,
verbose=verbose,
concurrent=concurrent,
deploy=deploy,
pre=pre,
requirements_dir=requirements_directory,
pypi_mirror=pypi_mirror,
)
# pip install:
with spinner():
c = pip_install(
package_name,
ignore_hashes=True,
allow_global=system,
selective_upgrade=selective_upgrade,
no_deps=False,
verbose=verbose,
pre=pre,
requirements_dir=requirements_directory.name,
index=index,
extra_indexes=extra_indexes,
pypi_mirror=pypi_mirror,
)
# Warn if --editable wasn't passed.
try:
converted = Requirement.from_line(package_name)
except ValueError as e:
click.echo('{0}: {1}'.format(crayons.red('WARNING'), e))
requirements_directory.cleanup()
sys.exit(1)
if converted.is_vcs and not converted.editable:
click.echo(
'{0}: You installed a VCS dependency in noneditable mode. '
'This will work fine, but sub-dependencies will not be resolved by {1}.'
'\n To enable this subdependency functionality, specify that this dependency is editable.'
''.format(
crayons.red('Warning', bold=True),
crayons.red('$ pipenv lock'),
)
)
click.echo(crayons.blue(format_pip_output(c.out)))
# Ensure that package was successfully installed.
try:
assert c.return_code == 0
except AssertionError:
# This is for if the user passed in dependencies, then we want to maek sure we
else:
for package_name in package_names:
click.echo(
'{0} An error occurred while installing {1}!'.format(
crayons.red('Error: ', bold=True),
crayons.green(package_name),
),
err=True,
crayons.normal(
u'Installing {0}...'.format(
crayons.green(package_name, bold=True)
),
bold=True,
)
)
click.echo(crayons.blue(format_pip_error(c.err)), err=True)
if 'setup.py egg_info' in c.err:
# pip install:
with spinner():
c = pip_install(
package_name,
ignore_hashes=True,
allow_global=system,
selective_upgrade=selective_upgrade,
no_deps=False,
verbose=verbose,
pre=pre,
requirements_dir=requirements_directory.name,
index=index,
extra_indexes=extra_indexes,
pypi_mirror=pypi_mirror,
)
# Warn if --editable wasn't passed.
try:
converted = Requirement.from_line(package_name)
except ValueError as e:
click.echo('{0}: {1}'.format(crayons.red('WARNING'), e))
requirements_directory.cleanup()
sys.exit(1)
if converted.is_vcs and not converted.editable:
click.echo(
'{0}: You installed a VCS dependency in non-editable mode. '
'This will work fine, but sub-dependencies will not be resolved by {1}.'
'\n To enable this sub-dependency functionality, specify that this dependency is editable.'
''.format(
crayons.red('Warning', bold=True),
crayons.red('$ pipenv lock'),
)
)
click.echo(crayons.blue(format_pip_output(c.out)))
# Ensure that package was successfully installed.
try:
assert c.return_code == 0
except AssertionError:
click.echo(
"This is likely caused by a bug in {0}. "
"Report this to its maintainers.".format(
'{0} An error occurred while installing {1}!'.format(
crayons.red('Error: ', bold=True),
crayons.green(package_name),
),
err=True,
)
requirements_directory.cleanup()
sys.exit(1)
click.echo(
'{0} {1} {2} {3}{4}'.format(
crayons.normal('Adding', bold=True),
crayons.green(package_name, bold=True),
crayons.normal("to Pipfile's", bold=True),
crayons.red(
'[dev-packages]' if dev else '[packages]', bold=True
),
crayons.normal('', bold=True),
)
)
# Add the package to the Pipfile.
try:
project.add_package_to_pipfile(package_name, dev)
except ValueError as e:
click.echo(crayons.blue(format_pip_error(c.err)), err=True)
if 'setup.py egg_info' in c.err:
click.echo(
"This is likely caused by a bug in {0}. "
"Report this to its maintainers.".format(
crayons.green(package_name),
),
err=True,
)
requirements_directory.cleanup()
sys.exit(1)
click.echo(
'{0} {1}'.format(
crayons.red('ERROR (PACKAGE NOT INSTALLED):'), e
'{0} {1} {2} {3}{4}'.format(
crayons.normal('Adding', bold=True),
crayons.green(package_name, bold=True),
crayons.normal("to Pipfile's", bold=True),
crayons.red(
'[dev-packages]' if dev else '[packages]', bold=True
),
crayons.normal('...', bold=True),
)
)
# Update project settings with pre preference.
if pre:
project.update_settings({'allow_prereleases': pre})
if lock and not skip_lock:
# Add the package to the Pipfile.
try:
project.add_package_to_pipfile(package_name, dev)
except ValueError as e:
click.echo(
'{0} {1}'.format(
crayons.red('ERROR (PACKAGE NOT INSTALLED):'), e
)
)
# Update project settings with pre preference.
if pre:
project.update_settings({'allow_prereleases': pre})
do_init(
dev=dev,
system=system,
@@ -2067,8 +2072,10 @@ def do_install(
requirements_dir=requirements_directory,
deploy=deploy,
pypi_mirror=pypi_mirror,
skip_lock=skip_lock
)
requirements_directory.cleanup()
requirements_directory.cleanup()
sys.exit(0)
def do_uninstall(
@@ -2095,7 +2102,7 @@ def do_uninstall(
if all is True:
click.echo(
crayons.normal(
u'Un-installing all packages from virtualenv', bold=True
u'Un-installing all packages from virtualenv...', bold=True
)
)
do_purge(allow_global=system, verbose=verbose)
@@ -2114,7 +2121,7 @@ def do_uninstall(
sys.exit(0)
click.echo(
crayons.normal(
u'Un-installing {0}'.format(crayons.red('[dev-packages]')),
u'Un-installing {0}...'.format(crayons.red('[dev-packages]')),
bold=True,
)
)
@@ -2124,7 +2131,7 @@ def do_uninstall(
click.echo(crayons.red('No package provided!'), err=True)
sys.exit(1)
for package_name in package_names:
click.echo(u'Un-installing {0}'.format(crayons.green(package_name)))
click.echo(u'Un-installing {0}...'.format(crayons.green(package_name)))
cmd = '{0} uninstall {1} -y'.format(
escape_grouped_arguments(which_pip(allow_global=system)),
package_name,
@@ -2147,7 +2154,7 @@ def do_uninstall(
continue
click.echo(
u'Removing {0} from Pipfile'.format(
u'Removing {0} from Pipfile...'.format(
crayons.green(package_name)
)
)
@@ -2254,7 +2261,7 @@ def inline_activate_virtualenv():
if not activate_this or not os.path.exists(activate_this):
click.echo(
u'{0}: activate_this.py not found. Your environment is most '
u'certainly not activated. Continuing anyway'
u'certainly not activated. Continuing anyway...'
u''.format(crayons.red('Warning', bold=True)),
err=True,
)
@@ -2265,7 +2272,7 @@ def inline_activate_virtualenv():
# Catch all errors, just in case.
except Exception:
click.echo(
u'{0}: There was an unexpected error while activating your virtualenv. Continuing anyway'
u'{0}: There was an unexpected error while activating your virtualenv. Continuing anyway...'
''.format(crayons.red('Warning', bold=True)),
err=True,
)
@@ -2273,7 +2280,12 @@ def inline_activate_virtualenv():
def do_run_nt(script):
import subprocess
p = subprocess.Popen(script.cmdify(), shell=True, universal_newlines=True)
command = system_which(script.command)
options = {'universal_newlines': True}
if command: # Try to use CreateProcess directly if possible.
p = subprocess.Popen([command] + script.args, **options)
else: # Command not found, maybe this is a shell built-in?
p = subprocess.Popen(script.cmdify(), shell=True, **options)
p.communicate()
sys.exit(p.returncode)
@@ -2320,14 +2332,14 @@ def do_run(command, args, three=None, python=False):
try:
script = project.build_script(command, args)
except ScriptEmptyError:
click.echo("Can't run script {0!r}—it's empty?", err=True)
click.echo("Can't run script {0!r}-it's empty?", err=True)
if os.name == 'nt':
do_run_nt(script)
else:
do_run_posix(script, command=command)
def do_check(three=None, python=False, system=False, unused=False, args=None):
def do_check(three=None, python=False, system=False, unused=False, ignore=None, args=None):
if not system:
# Ensure that virtualenv is available.
ensure_project(three=three, python=python, validate=False, warn=False)
@@ -2352,7 +2364,7 @@ def do_check(three=None, python=False, system=False, unused=False, args=None):
sys.exit(1)
else:
sys.exit(0)
click.echo(crayons.normal(u'Checking PEP 508 requirements', bold=True))
click.echo(crayons.normal(u'Checking PEP 508 requirements...', bold=True))
if system:
python = system_which('python')
else:
@@ -2390,7 +2402,7 @@ def do_check(three=None, python=False, system=False, unused=False, args=None):
else:
click.echo(crayons.green('Passed!'))
click.echo(
crayons.normal(u'Checking installed package safety', bold=True)
crayons.normal(u'Checking installed package safety...', bold=True)
)
path = pep508checker.__file__.rstrip('cdo')
path = os.sep.join(__file__.split(os.sep)[:-1] + ['patched', 'safety.zip'])
@@ -2398,9 +2410,14 @@ def do_check(three=None, python=False, system=False, unused=False, args=None):
python = which('python')
else:
python = system_which('python')
if ignore:
ignored = '--ignore {0}'.format('--ignore '.join(ignore))
click.echo(crayons.normal('Notice: Ignoring CVE(s) {0}'.format(crayons.yellow(', '.join(ignore)))), err=True)
else:
ignored = ''
c = delegator.run(
'"{0}" {1} check --json --key=1ab8d58f-5122e025-83674263-bc1e79e0'.format(
python, escape_grouped_arguments(path)
'"{0}" {1} check --json --key=1ab8d58f-5122e025-83674263-bc1e79e0 {2}'.format(
python, escape_grouped_arguments(path), ignored
)
)
try:
@@ -2434,7 +2451,7 @@ def do_graph(bare=False, json=False, json_tree=False, reverse=False):
click.echo(
u'{0}: {1}'.format(
crayons.red('Warning', bold=True),
u'Unable to display currentlyinstalled dependency graph information here. '
u'Unable to display currently-installed dependency graph information here. '
u'Please run within a Pipenv project.',
),
err=True,
@@ -2627,7 +2644,7 @@ def do_clean(
else:
click.echo(
crayons.white(
'Uninstalling {0}'.format(repr(apparent_bad_package)),
'Uninstalling {0}...'.format(repr(apparent_bad_package)),
bold=True,
)
)
@@ -56,7 +56,7 @@ class LocalRequirementsRepository(BaseRepository):
if existing_pin and ireq_satisfied_by_existing_pin(ireq, existing_pin):
project, version, _ = as_tuple(existing_pin)
return make_install_requirement(
project, version, ireq.extras, constraint=ireq.constraint
project, version, ireq.extras, constraint=ireq.constraint, markers=ireq.markers
)
else:
return self.repository.find_best_match(ireq, prereleases)
+81 -46
View File
@@ -24,14 +24,15 @@ from .._compat import (
from pipenv.patched.notpip._vendor.packaging.requirements import InvalidRequirement, Requirement
from pipenv.patched.notpip._vendor.packaging.version import Version, InvalidVersion, parse as parse_version
from pipenv.patched.notpip._vendor.packaging.specifiers import SpecifierSet, InvalidSpecifier
from pipenv.patched.notpip._vendor.packaging.specifiers import SpecifierSet, InvalidSpecifier, Specifier
from pipenv.patched.notpip._vendor.packaging.markers import Marker, Op, Value, Variable
from pipenv.patched.notpip._vendor.pyparsing import ParseException
from ..cache import CACHE_DIR
from pipenv.environments import PIPENV_CACHE_DIR
from ..exceptions import NoCandidateFound
from ..utils import (fs_str, is_pinned_requirement, lookup_table, as_tuple, key_from_req,
make_install_requirement, format_requirement, dedup)
make_install_requirement, format_requirement, dedup, clean_requires_python)
from .base import BaseRepository
@@ -164,22 +165,7 @@ class PyPIRepository(BaseRepository):
if ireq.editable:
return ireq # return itself as the best match
py_version = parse_version(os.environ.get('PIP_PYTHON_VERSION', str(sys.version_info[:3])))
all_candidates = []
for c in self.find_all_candidates(ireq.name):
if c.requires_python:
# Old specifications had people setting this to single digits
# which is effectively the same as '>=digit,<digit+1'
if c.requires_python.isdigit():
c.requires_python = '>={0},<{1}'.format(c.requires_python, int(c.requires_python) + 1)
try:
specifier_set = SpecifierSet(c.requires_python)
except InvalidSpecifier:
pass
else:
if not specifier_set.contains(py_version):
continue
all_candidates.append(c)
all_candidates = clean_requires_python(self.find_all_candidates(ireq.name))
candidates_by_version = lookup_table(all_candidates, key=lambda c: c.version, unique=True)
try:
@@ -284,6 +270,20 @@ class PyPIRepository(BaseRepository):
os.makedirs(download_dir)
if not os.path.isdir(self._wheel_download_dir):
os.makedirs(self._wheel_download_dir)
# Collect setup_requires info from local eggs.
# Do this after we call the preparer on these reqs to make sure their
# egg info has been created
setup_requires = {}
dist = None
if ireq.editable:
try:
dist = ireq.get_dist()
if dist.has_metadata('requires.txt'):
setup_requires = self.finder.get_extras_links(
dist.get_metadata_lines('requires.txt')
)
except (TypeError, ValueError, AttributeError):
pass
try:
# Pip < 9 and below
@@ -320,7 +320,7 @@ class PyPIRepository(BaseRepository):
finder=self.finder,
session=self.session,
upgrade_strategy="to-satisfy-only",
force_reinstall=False,
force_reinstall=True,
ignore_dependencies=False,
ignore_requires_python=True,
ignore_installed=True,
@@ -330,33 +330,37 @@ class PyPIRepository(BaseRepository):
ignore_compatibility=False
)
self.resolver.resolve(reqset)
result = reqset.requirements.values()
result = set(reqset.requirements.values())
# Collect setup_requires info from local eggs.
# Do this after we call the preparer on these reqs to make sure their
# egg info has been created
setup_requires = {}
if ireq.editable:
# HACK: Sometimes the InstallRequirement doesn't properly get
# these values set on it during the resolution process. It's
# difficult to pin down what is going wrong. This fixes things.
if not getattr(ireq, 'version', None):
try:
dist = ireq.get_dist()
if dist.has_metadata('requires.txt'):
setup_requires = self.finder.get_extras_links(
dist.get_metadata_lines('requires.txt')
)
# HACK: Sometimes the InstallRequirement doesn't properly get
# these values set on it during the resolution process. It's
# difficult to pin down what is going wrong. This fixes things.
ireq.version = dist.version
ireq.project_name = dist.project_name
ireq.req = dist.as_requirement()
except (TypeError, ValueError):
dist = ireq.get_dist() if not dist else None
ireq.version = ireq.get_dist().version
except (ValueError, OSError, TypeError, AttributeError) as e:
pass
if not getattr(ireq, 'project_name', None):
try:
ireq.project_name = dist.project_name if dist else None
except (ValueError, TypeError) as e:
pass
if not getattr(ireq, 'req', None):
try:
ireq.req = dist.as_requirement() if dist else None
except (ValueError, TypeError) as e:
pass
# Convert setup_requires dict into a somewhat usable form.
if setup_requires:
for section in setup_requires:
python_version = section
not_python = not (section.startswith('[') and ':' in section)
# This is for cleaning up :extras: formatted markers
# by adding them to the results of the resolver
# since any such extra would have been returned as a result anyway
for value in setup_requires[section]:
# This is a marker.
if value.startswith('[') and ':' in value:
@@ -370,17 +374,43 @@ class PyPIRepository(BaseRepository):
try:
if not not_python:
result = result + [InstallRequirement.from_line("{0}{1}".format(value, python_version).replace(':', ';'))]
# Anything could go wrong here can't be too careful.
# Anything could go wrong here -- can't be too careful.
except Exception:
pass
# this section properly creates 'python_version' markers for cross-python
# virtualenv creation and for multi-python compatibility.
requires_python = reqset.requires_python if hasattr(reqset, 'requires_python') else self.resolver.requires_python
if requires_python:
marker = 'python_version=="{0}"'.format(requires_python.replace(' ', ''))
new_req = InstallRequirement.from_line('{0}; {1}'.format(str(ireq.req), marker))
result = [new_req]
marker_str = ''
# This corrects a logic error from the previous code which said that if
# we Encountered any 'requires_python' attributes, basically only create a
# single result no matter how many we resolved. This should fix
# a majority of the remaining non-deterministic resolution issues.
if any(requires_python.startswith(op) for op in Specifier._operators.keys()):
# We are checking first if we have leading specifier operator
# if not, we can assume we should be doing a == comparison
specifierset = list(SpecifierSet(requires_python))
# for multiple specifiers, the correct way to represent that in
# a specifierset is `Requirement('fakepkg; python_version<"3.0,>=2.6"')`
marker_key = Variable('python_version')
markers = []
for spec in specifierset:
operator, val = spec._spec
operator = Op(operator)
val = Value(val)
markers.append(''.join([marker_key.serialize(), operator.serialize(), val.serialize()]))
marker_str = ' and '.join(markers)
# The best way to add markers to a requirement is to make a separate requirement
# with only markers on it, and then to transfer the object istelf
marker_to_add = Requirement('fakepkg; {0}'.format(marker_str)).marker
result.remove(ireq)
ireq.req.marker = marker_to_add
result.add(ireq)
self._dependencies_cache[ireq] = result
reqset.cleanup_files()
return set(self._dependencies_cache[ireq])
def get_hashes(self, ireq):
@@ -399,11 +429,16 @@ class PyPIRepository(BaseRepository):
# We need to get all of the candidates that match our current version
# pin, these will represent all of the files that could possibly
# satisfy this constraint.
all_candidates = self.find_all_candidates(ireq.name)
candidates_by_version = lookup_table(all_candidates, key=lambda c: c.version)
matching_versions = list(
ireq.specifier.filter((candidate.version for candidate in all_candidates)))
matching_candidates = candidates_by_version[matching_versions[0]]
### Modification -- this is much more efficient....
### modification again -- still more efficient
matching_candidates = (
c for c in clean_requires_python(self.find_all_candidates(ireq.name))
if c.version in ireq.specifier
)
# candidates_by_version = lookup_table(all_candidates, key=lambda c: c.version)
# matching_versions = list(
# ireq.specifier.filter((candidate.version for candidate in all_candidates)))
# matching_candidates = candidates_by_version[matching_versions[0]]
return {
self._hash_cache.get_hash(candidate.location)
+18 -1
View File
@@ -11,13 +11,30 @@ from contextlib import contextmanager
from ._compat import InstallRequirement
from first import first
from pip._vendor.packaging.specifiers import SpecifierSet, InvalidSpecifier
from .click import style
UNSAFE_PACKAGES = {'setuptools', 'distribute', 'pip'}
def clean_requires_python(candidates):
"""Get a cleaned list of all the candidates with valid specifiers in the `requires_python` attributes."""
all_candidates = []
for c in candidates:
if c.requires_python:
# Old specifications had people setting this to single digits
# which is effectively the same as '>=digit,<digit+1'
if c.requires_python.isdigit():
c.requires_python = '>={0},<{1}'.format(c.requires_python, int(c.requires_python) + 1)
try:
SpecifierSet(c.requires_python)
except InvalidSpecifier:
continue
all_candidates.append(c)
return all_candidates
def key_from_ireq(ireq):
"""Get a standardized key for an InstallRequirement."""
if ireq.req is None and ireq.link is not None:
+6 -6
View File
@@ -40,9 +40,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.sp
\fBPipenv\fP\ the officially recommended Python packaging tool from \fI\%Python.org\fP, free (as in freedom).
.sp
Pipenv is a tool that aims to bring the best of all packaging worlds (bundler, composer, npm, cargo, yarn, etc.) to the Python world. \fIWindows is a firstclass citizen, in our world.\fP
Pipenv is a tool that aims to bring the best of all packaging worlds (bundler, composer, npm, cargo, yarn, etc.) to the Python world. \fIWindows is a first-class citizen, in our world.\fP
.sp
It automatically creates and manages a virtualenv for your projects, as well as adds/removes packages from your \fBPipfile\fP as you install/uninstall packages. It also generates the everimportant \fBPipfile.lock\fP, which is used to produce deterministic builds.
It automatically creates and manages a virtualenv for your projects, as well as adds/removes packages from your \fBPipfile\fP as you install/uninstall packages. It also generates the ever-important \fBPipfile.lock\fP, which is used to produce deterministic builds.
.sp
The problems that Pipenv seeks to solve are multi\-faceted:
.INDENT 0.0
@@ -670,7 +670,7 @@ Note the inclusion of \fB[requires] python_version = "3.6"\fP\&. This specifies
of Python, and will be used automatically when running \fBpipenv install\fP against this \fBPipfile\fP in the future
(e.g. on other machines). If this is not true, feel free to simply remove this section.
.sp
If you don\(aqt specify a Python version on the commandline, either the \fB[requires]\fP \fBpython_full_version\fP or \fBpython_version\fP will be selected
If you don\(aqt specify a Python version on the command-line, either the \fB[requires]\fP \fBpython_full_version\fP or \fBpython_version\fP will be selected
automatically, falling back to whatever your system\(aqs default \fBpython\fP installation is, at time of execution.
.SS Editable Dependencies (e.g. \fB\-e .\fP )
.sp
@@ -800,7 +800,7 @@ The shell launched in interactive mode. This means that if your shell reads its
.UNINDENT
.SS A Note about VCS Dependencies
.sp
Pipenv will resolve the subdependencies of VCS dependencies, but only if they are editable, like so:
Pipenv will resolve the sub-dependencies of VCS dependencies, but only if they are editable, like so:
.INDENT 0.0
.INDENT 3.5
.sp
@@ -813,7 +813,7 @@ requests = {git = "https://github.com/requests/requests.git", editable=true}
.UNINDENT
.UNINDENT
.sp
If editable is not true, subdependencies will not get resolved.
If editable is not true, sub-dependencies will not get resolved.
.SS Pipfile.lock Security Features
.sp
\fBPipfile.lock\fP takes advantage of some great new security improvements in \fBpip\fP\&.
@@ -931,7 +931,7 @@ $ pipenv install \-\-system \-\-deploy
.UNINDENT
.UNINDENT
.sp
This will fail a build if the \fBPipfile.lock\fP is outofdate, instead of generating a new one.
This will fail a build if the \fBPipfile.lock\fP is out-of-date, instead of generating a new one.
.SS Generating a \fBrequirements.txt\fP
.sp
You can convert a \fBPipfile\fP and \fBPipenv.lock\fP into a \fBrequirements.txt\fP file very easily, and get all the benefits of hashes, extras, and other goodies we have included.
+73 -49
View File
@@ -220,7 +220,9 @@ def prepare_pip_source_args(sources, pip_args=None):
def actually_resolve_deps(
deps, index_lookup, markers_lookup, project, sources, verbose, clear, pre, req_dir=None
):
from .vendor.packaging.markers import default_environment
from .patched.notpip._internal import basecommand
from .patched.notpip._internal.cmdoptions import no_binary, only_binary
from .patched.notpip._internal.req import parse_requirements
from .patched.notpip._internal.exceptions import DistributionNotFound
from .patched.notpip._vendor.requests.exceptions import HTTPError
@@ -248,51 +250,50 @@ def actually_resolve_deps(
dep, url = dep.split(' -i ')
req = Requirement.from_line(dep)
# req.as_line() is theoratically the same as dep, but is guaranteed to
# be normalized. This is safer than passing in dep.
# TODO: Stop passing dep lines around; just use requirement objects.
constraints.append(req.constraint_line)
# extra_constraints = []
if url:
index_lookup[req.name] = project.get_source(url=url).get('name')
# strip the marker and re-add it later after resolution
# but we will need a fallback in case resolution fails
# eg pypiwin32
if req.markers:
markers_lookup[req.name] = req.markers.replace('"', "'")
constraints_file = None
constraints.append(req.constraint_line)
pip_command = get_pip_command()
constraints_file = None
pip_args = []
if sources:
pip_args = prepare_pip_source_args(sources, pip_args)
if verbose:
print('Using pip: {0}'.format(' '.join(pip_args)))
with NamedTemporaryFile(mode='w', prefix='pipenv-', suffix='-constraints.txt', dir=req_dir.name, delete=False) as f:
if sources:
requirementstxt_sources = ' '.join(pip_args).replace(' --', '\n--')
requirementstxt_sources = ' '.join(pip_args) if pip_args else ''
requirementstxt_sources = requirementstxt_sources.replace(' --', '\n--')
f.write(u'{0}\n'.format(requirementstxt_sources))
f.write(u'\n'.join([_constraint for _constraint in constraints]))
constraints_file = f.name
if verbose:
print('Using pip: {0}'.format(' '.join(pip_args)))
pip_args = pip_args.extend(['--cache-dir', PIPENV_CACHE_DIR])
pip_options, _ = pip_command.parse_args(pip_args)
pip_options, _ = pip_command.parser.parse_args(pip_args)
pip_options.cache_dir = PIPENV_CACHE_DIR
session = pip_command._build_session(pip_options)
pypi = PyPIRepository(
pip_options=pip_options, use_json=False, session=session
)
constraints = parse_requirements(constraints_file, finder=pypi.finder, session=pypi.session, options=pip_options)
constraints = [c for c in constraints]
if verbose:
logging.log.verbose = True
piptools_logging.log.verbose = True
resolved_tree = set()
resolver = Resolver(
constraints=parse_requirements(
constraints_file,
finder=pypi.finder, session=pypi.session, options=pip_options,
),
repository=pypi,
clear_caches=clear,
prereleases=pre,
)
resolver = Resolver(constraints=constraints, repository=pypi, clear_caches=clear, prereleases=pre)
# pre-resolve instead of iterating to avoid asking pypi for hashes of editable packages
hashes = None
try:
resolved_tree.update(resolver.resolve(max_rounds=PIPENV_MAX_ROUNDS))
results = resolver.resolve(max_rounds=PIPENV_MAX_ROUNDS)
hashes = resolver.resolve_hashes(results)
resolved_tree.update(results)
except (NoCandidateFound, DistributionNotFound, HTTPError) as e:
click_echo(
'{0}: Your dependencies could not be resolved. You likely have a '
@@ -320,8 +321,7 @@ def actually_resolve_deps(
raise RuntimeError
if cleanup_req_dir:
req_dir.cleanup()
return resolved_tree, resolver
return (resolved_tree, hashes, markers_lookup, resolver)
def venv_resolve_deps(
@@ -373,7 +373,7 @@ def resolve_deps(
python=False,
clear=False,
pre=False,
allow_global=False,
allow_global=False
):
"""Given a list of dependencies, return a resolved list of dependencies,
using pip-tools -- and their hashes, using the warehouse API / pip.
@@ -391,7 +391,7 @@ def resolve_deps(
req_dir = TemporaryDirectory(prefix='pipenv-', suffix='-requirements')
with HackedPythonVersion(python_version=python, python_path=python_path):
try:
resolved_tree, resolver = actually_resolve_deps(
resolved_tree, hashes, markers_lookup, resolver = actually_resolve_deps(
deps,
index_lookup,
markers_lookup,
@@ -400,7 +400,7 @@ def resolve_deps(
verbose,
clear,
pre,
req_dir=req_dir,
req_dir=req_dir
)
except RuntimeError:
# Don't exit here, like usual.
@@ -414,7 +414,7 @@ def resolve_deps(
try:
# Attempt to resolve again, with different Python version information,
# particularly for particularly particular packages.
resolved_tree, resolver = actually_resolve_deps(
resolved_tree, hashes, markers_lookup, resolver = actually_resolve_deps(
deps,
index_lookup,
markers_lookup,
@@ -423,7 +423,7 @@ def resolve_deps(
verbose,
clear,
pre,
req_dir=req_dir,
req_dir=req_dir
)
except RuntimeError:
req_dir.cleanup()
@@ -442,7 +442,9 @@ def resolve_deps(
else:
markers = markers_lookup.get(result.name)
collected_hashes = []
if any('python.org' in source['url'] or 'pypi.org' in source['url']
if result in hashes:
collected_hashes = list(hashes.get(result))
elif any('python.org' in source['url'] or 'pypi.org' in source['url']
for source in sources):
pkg_url = 'https://pypi.org/pypi/{0}/json'.format(name)
session = _get_requests_session()
@@ -466,14 +468,14 @@ def resolve_deps(
crayons.red('Warning', bold=True), name
)
)
# Collect un-collectable hashes (should work with devpi).
try:
collected_hashes = collected_hashes + list(
list(resolver.resolve_hashes([result]).items())[0][1]
)
except (ValueError, KeyError, ConnectionError, IndexError):
if verbose:
print('Error generating hash for {}'.format(name))
# # Collect un-collectable hashes (should work with devpi).
# try:
# collected_hashes = collected_hashes + list(
# list(resolver.resolve_hashes([result]).items())[0][1]
# )
# except (ValueError, KeyError, ConnectionError, IndexError):
# if verbose:
# print('Error generating hash for {}'.format(name))
collected_hashes = sorted(set(collected_hashes))
d = {'name': name, 'version': version, 'hashes': collected_hashes}
if index:
@@ -854,11 +856,6 @@ def path_to_url(path):
return Path(normalize_drive(os.path.abspath(path))).as_uri()
def get_converted_relative_path(path, relative_to=os.curdir):
"""Given a vague relative path, return the path relative to the given location"""
return os.path.join('.', os.path.relpath(path, start=relative_to))
def walk_up(bottom):
"""Mimic os.walk, but walk 'up' instead of down the directory tree.
From: https://gist.github.com/zdavkeos/1098474
@@ -1195,9 +1192,34 @@ def get_vcs_deps(
return reqs, lockfile
def clean_resolved_dep(dep, is_top_level=False, pipfile_entry=None):
def translate_markers(pipfile_entry):
"""Take a pipfile entry and normalize its markers
Provide a pipfile entry which may have 'markers' as a key or it may have
any valid key from `packaging.markers.marker_context.keys()` and standardize
the format into {'markers': 'key == "some_value"'}.
:param pipfile_entry: A dictionariy of keys and values representing a pipfile entry
:type pipfile_entry: dict
:returns: A normalized dictionary with cleaned marker entries
"""
if not isinstance(pipfile_entry, Mapping):
raise TypeError('Entry is not a pipfile formatted mapping.')
from notpip._vendor.distlib.markers import DEFAULT_CONTEXT as marker_context
allowed_marker_keys = ['markers'] + [k for k in marker_context.keys()]
provided_keys = list(pipfile_entry.keys()) if hasattr(pipfile_entry, 'keys') else []
pipfile_marker = next((k for k in provided_keys if k in allowed_marker_keys), None)
new_pipfile = dict(pipfile_entry).copy()
if pipfile_marker:
entry = "{0}".format(pipfile_entry[pipfile_marker])
if pipfile_marker != 'markers':
entry = "{0} {1}".format(pipfile_marker, entry)
new_pipfile.pop(pipfile_marker)
new_pipfile['markers'] = entry
return new_pipfile
def clean_resolved_dep(dep, is_top_level=False, pipfile_entry=None):
name = pep423_name(dep['name'])
# We use this to determine if there are any markers on top level packages
# So we can make sure those win out during resolution if the packages reoccur
@@ -1226,16 +1248,18 @@ def clean_resolved_dep(dep, is_top_level=False, pipfile_entry=None):
if 'markers' in dep:
# First, handle the case where there is no top level dependency in the pipfile
if not is_top_level:
lockfile['markers'] = dep['markers']
try:
lockfile['markers'] = translate_markers(dep)['markers']
except TypeError:
pass
# otherwise make sure we are prioritizing whatever the pipfile says about the markers
# If the pipfile says nothing, then we should put nothing in the lockfile
else:
pipfile_marker = next((k for k in dep_keys if k in allowed_marker_keys), None)
if pipfile_marker:
entry = "{0}".format(pipfile_entry[pipfile_marker])
if pipfile_marker != 'markers':
entry = "{0} {1}".format(pipfile_marker, entry)
lockfile['markers'] = entry
try:
pipfile_entry = translate_markers(pipfile_entry)
lockfile['markers'] = pipfile_entry.get('markers')
except TypeError:
pass
return {name: lockfile}
+1 -1
View File
@@ -1,5 +1,5 @@
# -*- coding=utf-8 -*-
__version__ = "1.0.1"
__version__ = "1.0.5.dev0"
from .exceptions import RequirementError
+4 -3
View File
@@ -9,8 +9,8 @@ from .._compat import Path, FileNotFoundError
@attr.s
class Lockfile(object):
dev_requirements = attr.ib(default=list)
requirements = attr.ib(default=list)
dev_requirements = attr.ib(default=attr.Factory(list))
requirements = attr.ib(default=attr.Factory(list))
path = attr.ib(default=None, validator=optional_instance_of(Path))
pipfile_hash = attr.ib(default=None)
@@ -31,7 +31,8 @@ class Lockfile(object):
if not lockfile_path.exists():
raise FileNotFoundError("No such lockfile: %s" % lockfile_path)
lockfile = json.loads(lockfile_path.read_text(encoding="utf-8"))
with lockfile_path.open(encoding="utf-8") as f:
lockfile = json.loads(f.read())
for k in lockfile["develop"].keys():
dev_requirements.append(Requirement.from_pipfile(k, lockfile["develop"][k]))
for k in lockfile["default"].keys():
+8 -5
View File
@@ -324,7 +324,7 @@ class FileRequirement(BaseRequirement):
vcs_type, prefer, relpath, path, uri, link = cls.get_link_from_line(line)
setup_path = Path(path) / "setup.py" if path else None
arg_dict = {
"path": relpath or path,
"path": relpath if relpath else path,
"uri": unquote(link.url_without_fragment),
"link": link,
"editable": editable,
@@ -347,6 +347,11 @@ class FileRequirement(BaseRequirement):
uri = pipfile.get("uri")
fil = pipfile.get("file")
path = pipfile.get("path")
if path:
if isinstance(path, Path) and not path.is_absolute():
path = get_converted_relative_path(path.as_posix())
elif not os.path.isabs(path):
path = get_converted_relative_path(path)
if path and uri:
raise ValueError("do not specify both 'path' and 'uri'")
if path and fil:
@@ -387,7 +392,7 @@ class FileRequirement(BaseRequirement):
):
seed = unquote(self.link.url_without_fragment) or self.uri
else:
seed = self.formatted_path or self.link.url or self.uri
seed = self.formatted_path or unquote(self.link.url_without_fragment) or self.uri
# add egg fragments to remote artifacts (valid urls only)
if not self._has_hashed_name and self.is_remote_artifact:
seed += "#egg={0}".format(self.name)
@@ -789,9 +794,7 @@ class Requirement(object):
@property
def constraint_line(self):
if self.is_named or self.is_vcs:
return self.as_line()
return self.req.req.line
return self.as_line()
def as_pipfile(self):
good_keys = (
+1 -1
View File
@@ -84,7 +84,7 @@ def strip_ssh_from_git_uri(uri):
def add_ssh_scheme_to_git_uri(uri):
"""Cleans VCS uris from pipenv.patched.notpip format"""
"""Cleans VCS uris from pip format"""
if isinstance(uri, six.string_types):
# Add scheme for parsing purposes, this is also what pip does
if uri.startswith("git+") and "://" not in uri:
+15 -6
View File
@@ -2,6 +2,7 @@
from __future__ import absolute_import
import logging
import os
import posixpath
import six
from itertools import product
@@ -60,17 +61,25 @@ def is_vcs(pipfile_entry):
def get_converted_relative_path(path, relative_to=os.curdir):
"""Given a vague relative path, return the path relative to the given location"""
"""Convert `path` to be relative.
Given a vague relative path, return the path relative to the given
location.
This performs additional conversion to ensure the result is of POSIX form,
and starts with `./`, or is precisely `.`.
"""
start = Path(relative_to)
try:
start = start.resolve()
except OSError:
start = start.absolute()
path = start.joinpath(".", path).relative_to(start)
# Normalize these to use forward slashes even on windows
if os.name == "nt":
return os.altsep.join([".", path.as_posix()])
return os.sep.join([".", path.as_posix()])
path = start.joinpath(path).relative_to(start)
relpath_s = posixpath.normpath(path.as_posix())
if not (relpath_s == "." or relpath_s.startswith("./")):
relpath_s = posixpath.join(".", relpath_s)
return relpath_s
def multi_split(s, split):
+1 -1
View File
@@ -27,7 +27,7 @@ requests==2.19.1
idna==2.7
urllib3==1.23
certifi==2018.4.16
requirementslib==1.0.1
requirementslib==1.0.5
attrs==18.1.0
distlib==0.2.7
packaging==17.1
+1 -1
View File
@@ -104,7 +104,7 @@ setup(
author='Kenneth Reitz',
author_email='me@kennethreitz.org',
url='https://github.com/pypa/pipenv',
packages=find_packages(exclude=['tests']),
packages=find_packages(exclude=['tests', 'tasks']),
entry_points={
'console_scripts': [
'pipenv=pipenv:cli',
+6 -3
View File
@@ -58,11 +58,11 @@ def generate_changelog(ctx, commit=False, draft=False):
if draft:
commit = False
log('Writing draft to file...')
ctx.run('towncrier --draft > CHANGELOG.rst')
ctx.run('towncrier --draft > CHANGELOG.draft.rst')
if commit:
ctx.run('towncrier')
log('Committing...')
ctx.run('git add .')
ctx.run('git add CHANGELOG.rst')
ctx.run('git commit -m "Update changelog."')
@@ -77,7 +77,7 @@ def tag_version(ctx, push=False):
@invoke.task
def bump_version(ctx, dry_run=False, increment=True, release=False, dev=False, pre=False, tag=None, clear=False):
def bump_version(ctx, dry_run=False, increment=True, release=False, dev=False, pre=False, tag=None, clear=False, commit=False,):
current_version = Version.parse(__version__)
today = datetime.date.today()
next_month_number = today.month + 1 if today.month != 12 else 1
@@ -111,3 +111,6 @@ def bump_version(ctx, dry_run=False, increment=True, release=False, dev=False, p
else:
log('Updating to: %s' % new_version.normalize())
version_file.write_text(file_contents.replace(__version__, str(new_version.normalize())))
if commit:
log('Committing...')
ctx.run('git commit -s -m "Bumped version."')
+157 -54
View File
@@ -19,7 +19,7 @@ index 4e6174c..75f9b49 100644
# NOTE
# We used to store the cache dir under ~/.pip-tools, which is not the
diff --git a/pipenv/patched/piptools/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py
index 1c4b943..7c6521d 100644
index 1c4b943..07cd667 100644
--- a/pipenv/patched/piptools/repositories/pypi.py
+++ b/pipenv/patched/piptools/repositories/pypi.py
@@ -4,6 +4,7 @@ from __future__ import (absolute_import, division, print_function,
@@ -30,7 +30,7 @@ index 1c4b943..7c6521d 100644
from contextlib import contextmanager
from shutil import rmtree
@@ -15,13 +16,23 @@ from .._compat import (
@@ -15,13 +16,24 @@ from .._compat import (
Wheel,
FAVORITE_HASH,
TemporaryDirectory,
@@ -43,7 +43,8 @@ index 1c4b943..7c6521d 100644
+from pip._vendor.packaging.requirements import InvalidRequirement, Requirement
+from pip._vendor.packaging.version import Version, InvalidVersion, parse as parse_version
+from pip._vendor.packaging.specifiers import SpecifierSet, InvalidSpecifier
+from pip._vendor.packaging.specifiers import SpecifierSet, InvalidSpecifier, Specifier
+from pip._vendor.packaging.markers import Marker, Op, Value, Variable
+from pip._vendor.pyparsing import ParseException
+
from ..cache import CACHE_DIR
@@ -52,12 +53,12 @@ index 1c4b943..7c6521d 100644
-from ..utils import (fs_str, is_pinned_requirement, lookup_table,
- make_install_requirement)
+from ..utils import (fs_str, is_pinned_requirement, lookup_table, as_tuple, key_from_req,
+ make_install_requirement, format_requirement, dedup)
+ make_install_requirement, format_requirement, dedup, clean_requires_python)
+
from .base import BaseRepository
@@ -37,6 +48,40 @@ except ImportError:
@@ -37,6 +49,40 @@ except ImportError:
from pip.wheel import WheelCache
@@ -98,7 +99,7 @@ index 1c4b943..7c6521d 100644
class PyPIRepository(BaseRepository):
DEFAULT_INDEX_URL = PyPI.simple_url
@@ -46,10 +91,11 @@ class PyPIRepository(BaseRepository):
@@ -46,10 +92,11 @@ class PyPIRepository(BaseRepository):
config), but any other PyPI mirror can be used if index_urls is
changed/configured on the Finder.
"""
@@ -112,7 +113,7 @@ index 1c4b943..7c6521d 100644
index_urls = [pip_options.index_url] + pip_options.extra_index_urls
if pip_options.no_index:
@@ -74,11 +120,15 @@ class PyPIRepository(BaseRepository):
@@ -74,11 +121,15 @@ class PyPIRepository(BaseRepository):
# of all secondary dependencies for the given requirement, so we
# only have to go to disk once for each requirement
self._dependencies_cache = {}
@@ -130,27 +131,12 @@ index 1c4b943..7c6521d 100644
def freshen_build_caches(self):
"""
@@ -114,10 +164,29 @@ class PyPIRepository(BaseRepository):
@@ -114,10 +165,14 @@ class PyPIRepository(BaseRepository):
if ireq.editable:
return ireq # return itself as the best match
- all_candidates = self.find_all_candidates(ireq.name)
+ py_version = parse_version(os.environ.get('PIP_PYTHON_VERSION', str(sys.version_info[:3])))
+ all_candidates = []
+ for c in self.find_all_candidates(ireq.name):
+ if c.requires_python:
+ # Old specifications had people setting this to single digits
+ # which is effectively the same as '>=digit,<digit+1'
+ if c.requires_python.isdigit():
+ c.requires_python = '>={0},<{1}'.format(c.requires_python, int(c.requires_python) + 1)
+ try:
+ specifier_set = SpecifierSet(c.requires_python)
+ except InvalidSpecifier:
+ pass
+ else:
+ if not specifier_set.contains(py_version):
+ continue
+ all_candidates.append(c)
+ all_candidates = clean_requires_python(self.find_all_candidates(ireq.name))
+
candidates_by_version = lookup_table(all_candidates, key=lambda c: c.version, unique=True)
- matching_versions = ireq.specifier.filter((candidate.version for candidate in all_candidates),
@@ -162,7 +148,7 @@ index 1c4b943..7c6521d 100644
# Reuses pip's internal candidate sort key to sort
matching_candidates = [candidates_by_version[ver] for ver in matching_versions]
@@ -126,11 +195,71 @@ class PyPIRepository(BaseRepository):
@@ -126,11 +181,71 @@ class PyPIRepository(BaseRepository):
best_candidate = max(matching_candidates, key=self.finder._candidate_sort_key)
# Turn the candidate into a pinned InstallRequirement
@@ -237,6 +223,27 @@ index 1c4b943..7c6521d 100644
"""
Given a pinned or an editable InstallRequirement, returns a set of
dependencies (also InstallRequirements, but not necessarily pinned).
@@ -155,6 +270,20 @@ class PyPIRepository(BaseRepository):
os.makedirs(download_dir)
if not os.path.isdir(self._wheel_download_dir):
os.makedirs(self._wheel_download_dir)
+ # Collect setup_requires info from local eggs.
+ # Do this after we call the preparer on these reqs to make sure their
+ # egg info has been created
+ setup_requires = {}
+ dist = None
+ if ireq.editable:
+ try:
+ dist = ireq.get_dist()
+ if dist.has_metadata('requires.txt'):
+ setup_requires = self.finder.get_extras_links(
+ dist.get_metadata_lines('requires.txt')
+ )
+ except (TypeError, ValueError, AttributeError):
+ pass
try:
# Pip < 9 and below
@@ -164,11 +293,14 @@ class PyPIRepository(BaseRepository):
download_dir=download_dir,
wheel_download_dir=self._wheel_download_dir,
@@ -254,9 +261,12 @@ index 1c4b943..7c6521d 100644
)
except TypeError:
# Pip >= 10 (new resolver!)
@@ -190,14 +322,64 @@ class PyPIRepository(BaseRepository):
@@ -188,17 +320,97 @@ class PyPIRepository(BaseRepository):
finder=self.finder,
session=self.session,
upgrade_strategy="to-satisfy-only",
force_reinstall=False,
- force_reinstall=False,
+ force_reinstall=True,
ignore_dependencies=False,
- ignore_requires_python=False,
+ ignore_requires_python=True,
@@ -268,33 +278,37 @@ index 1c4b943..7c6521d 100644
)
self.resolver.resolve(reqset)
- self._dependencies_cache[ireq] = reqset.requirements.values()
+ result = reqset.requirements.values()
+ result = set(reqset.requirements.values())
+
+ # Collect setup_requires info from local eggs.
+ # Do this after we call the preparer on these reqs to make sure their
+ # egg info has been created
+ setup_requires = {}
+ if ireq.editable:
+ # HACK: Sometimes the InstallRequirement doesn't properly get
+ # these values set on it during the resolution process. It's
+ # difficult to pin down what is going wrong. This fixes things.
+ if not getattr(ireq, 'version', None):
+ try:
+ dist = ireq.get_dist()
+ if dist.has_metadata('requires.txt'):
+ setup_requires = self.finder.get_extras_links(
+ dist.get_metadata_lines('requires.txt')
+ )
+ # HACK: Sometimes the InstallRequirement doesn't properly get
+ # these values set on it during the resolution process. It's
+ # difficult to pin down what is going wrong. This fixes things.
+ ireq.version = dist.version
+ ireq.project_name = dist.project_name
+ ireq.req = dist.as_requirement()
+ except (TypeError, ValueError):
+ dist = ireq.get_dist() if not dist else None
+ ireq.version = ireq.get_dist().version
+ except (ValueError, OSError, TypeError, AttributeError) as e:
+ pass
+ if not getattr(ireq, 'project_name', None):
+ try:
+ ireq.project_name = dist.project_name if dist else None
+ except (ValueError, TypeError) as e:
+ pass
+ if not getattr(ireq, 'req', None):
+ try:
+ ireq.req = dist.as_requirement() if dist else None
+ except (ValueError, TypeError) as e:
+ pass
+
+ # Convert setup_requires dict into a somewhat usable form.
+ if setup_requires:
+ for section in setup_requires:
+ python_version = section
+ not_python = not (section.startswith('[') and ':' in section)
+
+ # This is for cleaning up :extras: formatted markers
+ # by adding them to the results of the resolver
+ # since any such extra would have been returned as a result anyway
+ for value in setup_requires[section]:
+ # This is a marker.
+ if value.startswith('[') and ':' in value:
@@ -308,21 +322,65 @@ index 1c4b943..7c6521d 100644
+ try:
+ if not not_python:
+ result = result + [InstallRequirement.from_line("{0}{1}".format(value, python_version).replace(':', ';'))]
+ # Anything could go wrong here can't be too careful.
+ # Anything could go wrong here -- can't be too careful.
+ except Exception:
+ pass
+
+ # this section properly creates 'python_version' markers for cross-python
+ # virtualenv creation and for multi-python compatibility.
+ requires_python = reqset.requires_python if hasattr(reqset, 'requires_python') else self.resolver.requires_python
+ if requires_python:
+ marker = 'python_version=="{0}"'.format(requires_python.replace(' ', ''))
+ new_req = InstallRequirement.from_line('{0}; {1}'.format(str(ireq.req), marker))
+ result = [new_req]
+ marker_str = ''
+ # This corrects a logic error from the previous code which said that if
+ # we Encountered any 'requires_python' attributes, basically only create a
+ # single result no matter how many we resolved. This should fix
+ # a majority of the remaining non-deterministic resolution issues.
+ if any(requires_python.startswith(op) for op in Specifier._operators.keys()):
+ # We are checking first if we have leading specifier operator
+ # if not, we can assume we should be doing a == comparison
+ specifierset = list(SpecifierSet(requires_python))
+ # for multiple specifiers, the correct way to represent that in
+ # a specifierset is `Requirement('fakepkg; python_version<"3.0,>=2.6"')`
+ marker_key = Variable('python_version')
+ markers = []
+ for spec in specifierset:
+ operator, val = spec._spec
+ operator = Op(operator)
+ val = Value(val)
+ markers.append(''.join([marker_key.serialize(), operator.serialize(), val.serialize()]))
+ marker_str = ' and '.join(markers)
+ # The best way to add markers to a requirement is to make a separate requirement
+ # with only markers on it, and then to transfer the object istelf
+ marker_to_add = Requirement('fakepkg; {0}'.format(marker_str)).marker
+ result.remove(ireq)
+ ireq.req.marker = marker_to_add
+ result.add(ireq)
+
+ self._dependencies_cache[ireq] = result
reqset.cleanup_files()
+
return set(self._dependencies_cache[ireq])
@@ -224,17 +406,10 @@ class PyPIRepository(BaseRepository):
matching_candidates = candidates_by_version[matching_versions[0]]
def get_hashes(self, ireq):
@@ -217,24 +429,22 @@ class PyPIRepository(BaseRepository):
# We need to get all of the candidates that match our current version
# pin, these will represent all of the files that could possibly
# satisfy this constraint.
- all_candidates = self.find_all_candidates(ireq.name)
- candidates_by_version = lookup_table(all_candidates, key=lambda c: c.version)
- matching_versions = list(
- ireq.specifier.filter((candidate.version for candidate in all_candidates)))
- matching_candidates = candidates_by_version[matching_versions[0]]
+ ### Modification -- this is much more efficient....
+ ### modification again -- still more efficient
+ matching_candidates = (
+ c for c in clean_requires_python(self.find_all_candidates(ireq.name))
+ if c.version in ireq.specifier
+ )
+ # candidates_by_version = lookup_table(all_candidates, key=lambda c: c.version)
+ # matching_versions = list(
+ # ireq.specifier.filter((candidate.version for candidate in all_candidates)))
+ # matching_candidates = candidates_by_version[matching_versions[0]]
return {
- self._get_file_hash(candidate.location)
@@ -462,11 +520,56 @@ index 05ec8fd..c5eb728 100644
def reverse_dependencies(self, ireqs):
non_editable = [ireq for ireq in ireqs if not ireq.editable]
diff --git a/pipenv/patched/piptools/repositories/local.py b/pipenv/patched/piptools/repositories/local.py
index 08dabe1..480ad1e 100644
--- a/pipenv/patched/piptools/repositories/local.py
+++ b/pipenv/patched/piptools/repositories/local.py
@@ -56,7 +56,7 @@ class LocalRequirementsRepository(BaseRepository):
if existing_pin and ireq_satisfied_by_existing_pin(ireq, existing_pin):
project, version, _ = as_tuple(existing_pin)
return make_install_requirement(
- project, version, ireq.extras, constraint=ireq.constraint
+ project, version, ireq.extras, constraint=ireq.constraint, markers=ireq.markers
)
else:
return self.repository.find_best_match(ireq, prereleases)
diff --git a/pipenv/patched/piptools/utils.py b/pipenv/patched/piptools/utils.py
index fde5816..1d732bf 100644
index fde5816..5827a55 100644
--- a/pipenv/patched/piptools/utils.py
+++ b/pipenv/patched/piptools/utils.py
@@ -43,16 +43,51 @@ def comment(text):
@@ -11,13 +11,30 @@ from contextlib import contextmanager
from ._compat import InstallRequirement
from first import first
-
+from pip._vendor.packaging.specifiers import SpecifierSet, InvalidSpecifier
from .click import style
UNSAFE_PACKAGES = {'setuptools', 'distribute', 'pip'}
+def clean_requires_python(candidates):
+ """Get a cleaned list of all the candidates with valid specifiers in the `requires_python` attributes."""
+ all_candidates = []
+ for c in candidates:
+ if c.requires_python:
+ # Old specifications had people setting this to single digits
+ # which is effectively the same as '>=digit,<digit+1'
+ if c.requires_python.isdigit():
+ c.requires_python = '>={0},<{1}'.format(c.requires_python, int(c.requires_python) + 1)
+ try:
+ SpecifierSet(c.requires_python)
+ except InvalidSpecifier:
+ continue
+ all_candidates.append(c)
+ return all_candidates
+
+
def key_from_ireq(ireq):
"""Get a standardized key for an InstallRequirement."""
if ireq.req is None and ireq.link is not None:
@@ -43,16 +60,51 @@ def comment(text):
return style(text, fg='green')
@@ -522,7 +625,7 @@ index fde5816..1d732bf 100644
def format_requirement(ireq, marker=None):
@@ -63,10 +98,10 @@ def format_requirement(ireq, marker=None):
@@ -63,10 +115,10 @@ def format_requirement(ireq, marker=None):
if ireq.editable:
line = '-e {}'.format(ireq.link)
else:
+8 -1
View File
@@ -82,7 +82,14 @@ def test_pipenv_graph_reverse(PipenvInstance, pypi):
def test_pipenv_check(PipenvInstance, pypi):
with PipenvInstance(pypi=pypi) as p:
p.pipenv('install requests==1.0.0')
assert 'requests' in p.pipenv('check').out
c = p.pipenv('check')
assert c.return_code != 0
assert 'requests' in c.out
p.pipenv('uninstall requests')
p.pipenv('install six')
c = p.pipenv('check --ignore 35015')
assert c.return_code == 0
assert 'Ignoring' in c.err
@pytest.mark.cli
+78
View File
@@ -2,7 +2,13 @@ import contextlib
import os
from pipenv.utils import temp_environ
from pipenv._compat import TemporaryDirectory
from pipenv.vendor import delegator
from pipenv.project import Project
try:
from pathlib import Path
except ImportError:
from pipenv.vendor.pathlib2 import Path
import pytest
@@ -267,6 +273,35 @@ def test_requirements_to_pipfile(PipenvInstance, pypi):
assert 'pysocks' in p.lockfile['default']
@pytest.mark.install
@pytest.mark.requirements
def test_skip_requirements_when_pipfile(PipenvInstance, pypi):
"""Ensure requirements.txt is NOT imported when
1. We do `pipenv install [package]`
2. A Pipfile already exists when we run `pipenv install`.
"""
with PipenvInstance(chdir=True, pypi=pypi) as p:
with open('requirements.txt', 'w') as f:
f.write('requests==2.18.1\n')
c = p.pipenv('install six')
assert c.return_code == 0
with open(p.pipfile_path, 'w') as f:
contents = """
[packages]
six = "*"
tablib = "<0.12"
""".strip()
f.write(contents)
c = p.pipenv('install')
assert 'tablib' in p.pipfile['packages']
assert 'tablib' in p.lockfile['default']
assert 'six' in p.pipfile['packages']
assert 'six' in p.lockfile['default']
assert 'requests' not in p.pipfile['packages']
assert 'requests' not in p.lockfile['default']
@pytest.mark.cli
@pytest.mark.clean
def test_clean_on_empty_venv(PipenvInstance, pypi):
@@ -277,6 +312,8 @@ def test_clean_on_empty_venv(PipenvInstance, pypi):
@pytest.mark.install
def test_install_does_not_extrapolate_environ(PipenvInstance, pypi):
"""Ensure environment variables are not expanded in lock file.
"""
with temp_environ(), PipenvInstance(pypi=pypi, chdir=True) as p:
os.environ['PYPI_URL'] = pypi.url
@@ -309,3 +346,44 @@ def test_editable_no_args(PipenvInstance):
c = p.pipenv('install -e')
assert c.return_code != 0
assert 'Please provide path to editable package' in c.err
@pytest.mark.install
@pytest.mark.virtualenv
def test_install_venv_project_directory(PipenvInstance, pypi):
"""Test pew's project functionality during virtualenv creation.
Since .venv virtualenvs are not created with pew, we need to swap to a
workon_home based virtualenv for this test.
"""
with PipenvInstance(pypi=pypi, chdir=True) as p:
with temp_environ(), TemporaryDirectory(prefix='pipenv-', suffix='temp_workon_home') as workon_home:
os.environ['WORKON_HOME'] = workon_home.name
if 'PIPENV_VENV_IN_PROJECT' in os.environ:
del os.environ['PIPENV_VENV_IN_PROJECT']
c = p.pipenv('install six')
assert c.return_code == 0
project = Project()
assert Path(project.virtualenv_location).joinpath('.project').exists()
@pytest.mark.deploy
@pytest.mark.system
def test_system_and_deploy_work(PipenvInstance, pypi):
with PipenvInstance(chdir=True, pypi=pypi) as p:
c = p.pipenv('install six requests')
assert c.return_code == 0
c = p.pipenv('--rm')
assert c.return_code == 0
c = delegator.run('virtualenv .venv')
assert c.return_code == 0
c = p.pipenv('install --system --deploy')
assert c.return_code == 0
c = p.pipenv('--rm')
assert c.return_code == 0
Path(p.pipfile_path).write_text(u"""
[packages]
requests
""".strip())
c = p.pipenv('install --system')
assert c.return_code == 0
@@ -127,7 +127,6 @@ funcsigs = "*"
@pytest.mark.complex
@flaky
@py3_only
@pytest.mark.skip(reason='This test is garbage and I hate it')
def test_resolver_unique_markers(PipenvInstance, pypi):
"""vcrpy has a dependency on `yarl` which comes with a marker
of 'python version in "3.4, 3.5, 3.6" - this marker duplicates itself:
+49 -16
View File
@@ -1,6 +1,6 @@
import os
import shutil
from pipenv.project import Project
try:
import pathlib
except ImportError:
@@ -16,36 +16,47 @@ from flaky import flaky
@pytest.mark.extras
@pytest.mark.install
@pytest.mark.local
@pytest.mark.skip(reason="I'm not mocking this.")
def test_local_extras_install(PipenvInstance, pypi):
with PipenvInstance(pypi=pypi) as p:
@pytest.mark.parametrize('line, pipfile', [
['-e .[dev]', {'testpipenv': {'path': '.', 'editable': True, 'extras': ['dev']}}]
])
def test_local_extras_install(PipenvInstance, pypi, line, pipfile):
"""Ensure -e .[extras] installs.
"""
with PipenvInstance(pypi=pypi, chdir=True) as p:
project = Project()
setup_py = os.path.join(p.path, 'setup.py')
with open(setup_py, 'w') as fh:
contents = """
from setuptools import setup, find_packages
setup(
name='test_pipenv',
name='testpipenv',
version='0.1',
description='Pipenv Test Package',
author='Pipenv Test',
author_email='test@pipenv.package',
license='PIPENV',
license='MIT',
packages=find_packages(),
install_requires=['tablib'],
extras_require={'dev': ['flake8', 'pylint']},
install_requires=[],
extras_require={'dev': ['six']},
zip_safe=False
)
""".strip()
fh.write(contents)
c = p.pipenv('install .[dev]')
project.write_toml({'packages': pipfile, 'dev-packages': {}})
c = p.pipenv('install')
assert c.return_code == 0
key = [k for k in p.pipfile['packages'].keys()][0]
dep = p.pipfile['packages'][key]
assert dep['path'] == '.'
assert dep['extras'] == ['dev']
assert key in p.lockfile['default']
assert 'dev' in p.lockfile['default'][key]['extras']
assert 'testpipenv' in p.lockfile['default']
assert p.lockfile['default']['testpipenv']['extras'] == ['dev']
assert 'six' in p.lockfile['default']
c = p.pipenv('--rm')
assert c.return_code == 0
project.write_toml({'packages': {}, 'dev-packages': {}})
c = p.pipenv('install {0}'.format(line))
assert c.return_code == 0
assert 'testpipenv' in p.pipfile['packages']
assert p.pipfile['packages']['testpipenv']['path'] == '.'
assert p.pipfile['packages']['testpipenv']['extras'] == ['dev']
assert 'six' in p.lockfile['default']
@pytest.mark.e
@@ -230,3 +241,25 @@ def test_install_local_file_collision(PipenvInstance, pypi):
assert target_package in p.pipfile['packages']
assert p.pipfile['packages'][target_package] == '*'
assert target_package in p.lockfile['default']
@pytest.mark.url
@pytest.mark.install
def test_install_local_uri_special_character(PipenvInstance, testsroot):
file_name = 'six-1.11.0+mkl-py2.py3-none-any.whl'
source_path = os.path.abspath(os.path.join(testsroot, 'test_artifacts', file_name))
with PipenvInstance() as p:
artifact_dir = 'artifacts'
artifact_path = os.path.join(p.path, artifact_dir)
mkdir_p(artifact_path)
shutil.copy(source_path, os.path.join(artifact_path, file_name))
with open(p.pipfile_path, 'w') as f:
contents = """
# Pre comment
[packages]
six = {{path = "./artifacts/{}"}}
""".format(file_name)
f.write(contents.strip())
c = p.pipenv('install')
assert c.return_code == 0
assert 'six' in p.lockfile['default']
+8 -10
View File
@@ -138,8 +138,8 @@ def test_install_editable_git_tag(PipenvInstance, pip_src_dir, pypi):
@pytest.mark.install
@pytest.mark.index
@pytest.mark.needs_internet
def test_install_named_index_alias(PipenvInstance, pypi):
with PipenvInstance(pypi=pypi) as p:
def test_install_named_index_alias(PipenvInstance):
with PipenvInstance() as p:
with open(p.pipfile_path, 'w') as f:
contents = """
[[source]]
@@ -191,20 +191,18 @@ def test_install_local_vcs_not_in_lockfile(PipenvInstance, pip_src_dir):
@pytest.mark.needs_internet
def test_get_vcs_refs(PipenvInstance, pip_src_dir):
with PipenvInstance(chdir=True) as p:
c = p.pipenv('install -e git+https://github.com/hynek/structlog.git@16.1.0#egg=structlog')
c = p.pipenv('install -e git+https://github.com/benjaminp/six.git@1.9.0#egg=six')
assert c.return_code == 0
assert 'structlog' in p.pipfile['packages']
assert 'structlog' in p.lockfile['default']
assert 'six' in p.pipfile['packages']
assert 'six' in p.lockfile['default']
assert p.lockfile['default']['structlog']['ref'] == 'a39f6906a268fb2f4c365042b31d0200468fb492'
assert p.lockfile['default']['six']['ref'] == '5efb522b0647f7467248273ec1b893d06b984a59'
pipfile = Path(p.pipfile_path)
new_content = pipfile.read_bytes().replace(b'16.1.0', b'18.1.0')
new_content = pipfile.read_bytes().replace(b'1.9.0', b'1.11.0')
pipfile.write_bytes(new_content)
c = p.pipenv('lock')
assert c.return_code == 0
assert p.lockfile['default']['structlog']['ref'] == 'a73fbd3a9c3cafb11f43168582083f839b883034'
assert 'structlog' in p.pipfile['packages']
assert 'structlog' in p.lockfile['default']
assert p.lockfile['default']['six']['ref'] == '15e31431af97e5e64b80af0a3f598d382bcdd49a'
assert 'six' in p.pipfile['packages']
assert 'six' in p.lockfile['default']
+26 -9
View File
@@ -262,8 +262,8 @@ def test_private_index_mirror_lock_requirements(PipenvInstance):
with temp_environ(), PipenvInstance(chdir=True) as p:
# Using pypi.python.org as pipenv-test-public-package is not
# included in the local pypi mirror
mirror_url = "https://pypi.python.org/simple"
os.environ.pop('PIPENV_TEST_INDEX', None)
mirror_url = os.environ.pop('PIPENV_TEST_INDEX', "https://pypi.kennethreitz.org/simple")
# os.environ.pop('PIPENV_TEST_INDEX', None)
with open(p.pipfile_path, 'w') as f:
contents = """
[[source]]
@@ -277,7 +277,7 @@ verify_ssl = true
name = "testpypi"
[packages]
pipenv-test-private-package = {version = "*", index = "testpypi"}
six = {version = "*", index = "testpypi"}
requests = "*"
""".strip()
f.write(contents)
@@ -307,12 +307,11 @@ requests = "==2.14.0"
""".strip().format(url=pypi.url)
f.write(contents)
os.environ['MY_ENV_VAR'] = 'simple'
c = p.pipenv('lock')
assert c.return_code == 0
assert 'requests' in p.lockfile['default']
del os.environ['MY_ENV_VAR']
with temp_environ():
os.environ['MY_ENV_VAR'] = 'simple'
c = p.pipenv('lock')
assert c.return_code == 0
assert 'requests' in p.lockfile['default']
with open(p.pipfile_path, 'w') as f:
contents = """
@@ -328,3 +327,21 @@ requests = "==2.14.0"
assert c.return_code == 0
assert 'requests' in p.lockfile['default']
@pytest.mark.lock
@pytest.mark.vcs
@pytest.mark.needs_internet
def lock_editable_vcs_without_install(PipenvInstance, pypi):
with PipenvInstance(pypi=pypi, chdir=True) as p:
with open(p.pipfile_path, 'w') as f:
f.write("""
[packages]
requests = {git = "https://github.com/requests/requests.git", ref = "master", editable = true}
""".strip())
c = p.pipenv('lock')
assert c.return_code == 0
assert 'requests' in p.lockfile['default']
assert 'idna' in p.lockfile['default']
assert 'chardet' in p.lockfile['default']
c = p.pipenv('install')
assert c.return_code == 0
+20 -5
View File
@@ -10,6 +10,7 @@ import pytest
from pipenv.core import activate_virtualenv
from pipenv.project import Project
from pipenv.vendor import delegator
try:
from pathlib import Path
@@ -42,17 +43,21 @@ def test_activate_virtualenv_no_source():
@pytest.mark.cli
def test_deploy_works(PipenvInstance, pypi):
with PipenvInstance(pypi=pypi) as p:
with PipenvInstance(pypi=pypi, chdir=True) as p:
with open(p.pipfile_path, 'w') as f:
contents = """
[packages]
requests = "==2.14.0"
flask = "==0.12.2"
[dev-packages]
pytest = "==3.1.1"
""".strip()
f.write(contents)
c = p.pipenv('install')
c = p.pipenv('install --verbose')
if c.return_code != 0:
assert c.err == '' or c.err is None
assert c.out == ''
assert c.return_code == 0
c = p.pipenv('lock')
assert c.return_code == 0
@@ -81,11 +86,21 @@ def test_update_locks(PipenvInstance, pypi):
fh.write(pipfile_contents)
c = p.pipenv('update requests')
assert c.return_code == 0
assert p.lockfile['default']['requests']['version'] == '==2.18.4'
assert p.lockfile['default']['requests']['version'] == '==2.19.1'
c = p.pipenv('run pip freeze')
assert c.return_code == 0
lines = c.out.splitlines()
assert 'requests==2.18.4' in [l.strip() for l in lines]
assert 'requests==2.19.1' in [l.strip() for l in lines]
@pytest.mark.project
@pytest.mark.proper_names
def test_proper_names_unamanged_virtualenv(PipenvInstance, pypi):
with PipenvInstance(chdir=True, pypi=pypi) as p:
c = delegator.run('python -m virtualenv .venv')
assert c.return_code == 0
project = Project()
assert project.proper_names == []
@pytest.mark.cli
@@ -108,4 +123,4 @@ def test_directory_with_leading_dash(PipenvInstance):
assert os.path.isdir(venv_path)
# Manually clean up environment, since PipenvInstance assumes that
# the virutalenv is in the project directory.
p.pipenv('--rm')
p.pipenv('--rm')
+1 -1
View File
@@ -22,7 +22,7 @@ def test_sync_error_without_lockfile(PipenvInstance, pypi):
@pytest.mark.lock
def test_mirror_lock_sync(PipenvInstance, pypi):
with temp_environ(), PipenvInstance(chdir=True) as p:
mirror_url = os.environ.pop('PIPENV_TEST_INDEX', "https://pypi.python.org/simple")
mirror_url = os.environ.pop('PIPENV_TEST_INDEX', "https://pypi.kennethreitz.org/simple")
assert 'pypi.org' not in mirror_url
with open(p.pipfile_path, 'w') as f:
f.write("""
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More