mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
Merge branch 'master' into bugfix-439
This commit is contained in:
@@ -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
@@ -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
@@ -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 +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 +0,0 @@
|
||||
Massive internal improvements to requirements parsing codebase, resolver, and error messaging.
|
||||
@@ -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 +0,0 @@
|
||||
Pipenv will now parse & capitalize ``platform_python_implementation`` markers.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed a bug with parsing and grouping old-style ``setup.py`` extras during resolution
|
||||
@@ -1 +0,0 @@
|
||||
Fixed a bug causing pipenv graph to throw unhelpful exceptions when running against empty or non-existent environments.
|
||||
@@ -1 +0,0 @@
|
||||
Virtualenv names will now appear in prompts for most Windows users.
|
||||
@@ -1 +0,0 @@
|
||||
Added support for cmder shell paths with spaces.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed a bug which caused ``--system`` to incorrectly abort when users were in a virtualenv.
|
||||
@@ -1 +0,0 @@
|
||||
Added an invoke task to generate patches against vendored dependencies.
|
||||
@@ -1 +0,0 @@
|
||||
Massive internal improvements to requirements parsing codebase, resolver, and error messaging.
|
||||
@@ -1 +0,0 @@
|
||||
Removed vendored ``cacert.pem`` which could cause issues for some users with custom certificate settings.
|
||||
@@ -1 +0,0 @@
|
||||
Removed vendored ``cacert.pem`` which could cause issues for some users with custom certificate settings.
|
||||
@@ -1 +0,0 @@
|
||||
Update documentation wording to clarify Pipenv's overall role in the packaging ecosystem.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed a regression which led to direct invocations of ``virtualenv``, rather than calling it by module.
|
||||
@@ -1 +0,0 @@
|
||||
Added nested JSON output to the ``pipenv graph`` command.
|
||||
@@ -1 +0,0 @@
|
||||
Added contribution documentation and guidelines.
|
||||
@@ -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 +0,0 @@
|
||||
Added instructions for supervisord compatibility.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed broken links to development philosophy and contribution documentation.
|
||||
@@ -1,2 +0,0 @@
|
||||
Dropped vendored pip 9 and vendored, patched, and migrated to pip 10.
|
||||
Updated patched piptools version.
|
||||
@@ -1,2 +0,0 @@
|
||||
Dropped vendored pip 9 and vendored, patched, and migrated to pip 10.
|
||||
Updated patched piptools version.
|
||||
@@ -1 +0,0 @@
|
||||
``pipenv clean`` will now correctly ignore comments from ``pip freeze`` when cleaning the environment.
|
||||
@@ -1 +0,0 @@
|
||||
Massive internal improvements to requirements parsing codebase, resolver, and error messaging.
|
||||
@@ -1 +0,0 @@
|
||||
Resolution bugs causing packages for incompatible python versions to be locked have been fixed.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed a bug causing pipenv graph to fail to display sometimes.
|
||||
@@ -1 +0,0 @@
|
||||
Updated ``requirementslib`` to fix a bug in pipfile parsing affecting relative path conversions.
|
||||
@@ -1 +0,0 @@
|
||||
Updated ``requirementslib`` to fix a bug in pipfile parsing affecting relative path conversions.
|
||||
@@ -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 +0,0 @@
|
||||
Virtualenv activation lines will now avoid being written to some shell history files.
|
||||
@@ -1 +0,0 @@
|
||||
Windows executable discovery now leverages ``os.pathext``.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed a bug which caused ``--deploy --system`` to inadvertently create a virtualenv before failing.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed an issue which led to a failure to unquote special characters in file and wheel paths.
|
||||
@@ -1 +0,0 @@
|
||||
VCS dependencies are now manually obtained only if they do not match the requested ref.
|
||||
@@ -1 +0,0 @@
|
||||
Change function name of ``pipenv.utils.actually_resolve_reps`` to ``pipenv.utils.actually_resolve_deps``.
|
||||
@@ -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 +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 +0,0 @@
|
||||
Removed unnecessary comma from documentation.
|
||||
@@ -1 +0,0 @@
|
||||
Massive internal improvements to requirements parsing codebase, resolver, and error messaging.
|
||||
@@ -1 +0,0 @@
|
||||
Added ``pipenv run`` suggestion for users who are first creating environment.
|
||||
@@ -1 +0,0 @@
|
||||
Added support for mounted drives via UNC paths.
|
||||
@@ -1 +0,0 @@
|
||||
Added support for Windows Subsystem for Linux bash shell detection.
|
||||
@@ -1 +0,0 @@
|
||||
Added custom shell detection library ``shellingham``, a port of our changes to ``pew``.
|
||||
@@ -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 +0,0 @@
|
||||
Added error handling functionality to properly cope with single-digit ``Requires-Python`` metatdata with no specifiers.
|
||||
@@ -1 +0,0 @@
|
||||
``pipenv update`` will now always run the resolver and lock before ensuring your dependencies are in sync with your lockfile.
|
||||
@@ -1 +0,0 @@
|
||||
Patched ``python-dotenv`` to ensure that environment variables always get encoded to the filesystem encoding.
|
||||
@@ -1 +0,0 @@
|
||||
Patched ``python-dotenv`` to ensure that environment variables always get encoded to the filesystem encoding.
|
||||
@@ -1 +0,0 @@
|
||||
Massive internal improvements to requirements parsing codebase, resolver, and error messaging.
|
||||
@@ -1 +0,0 @@
|
||||
Added release tasks for maintainers.
|
||||
@@ -2,4 +2,4 @@
|
||||
# // ) ) / / // ) ) //___) ) // ) ) || / /
|
||||
# //___/ / / / //___/ / // // / / || / /
|
||||
# // / / // ((____ // / / ||/ /
|
||||
__version__ = '2018.6.0.dev0'
|
||||
__version__ = '2018.6.25'
|
||||
|
||||
+24
-13
@@ -356,16 +356,16 @@ def cli(
|
||||
'--deploy',
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help=u"Abort if the Pipfile.lock is out–of–date, 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 pre–releases."
|
||||
'--pre', is_flag=True, default=False, help=u"Allow pre-releases."
|
||||
)
|
||||
@option(
|
||||
'--keep-outdated',
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help=u"Keep out–dated 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 out–dated 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 pre–releases."
|
||||
'--pre', is_flag=True, default=False, help=u"Allow pre-releases."
|
||||
)
|
||||
@option(
|
||||
'--keep-outdated',
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help=u"Keep out–dated 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 pre–releases."
|
||||
'--pre', is_flag=True, default=False, help=u"Allow pre-releases."
|
||||
)
|
||||
@option(
|
||||
'--keep-outdated',
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help=u"Keep out–dated 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 out–of–date dependencies.",
|
||||
help=u"List out-of-date dependencies.",
|
||||
)
|
||||
@option(
|
||||
'--dry-run',
|
||||
is_flag=True,
|
||||
default=None,
|
||||
help=u"List out–of–date 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 currently–installed 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
@@ -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 initially–failed 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 up–to–date."""
|
||||
"""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} out–of–date: {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 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:
|
||||
|
||||
# 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 currently–installed 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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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 first–class 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 ever–important \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 command–line, 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 sub–dependencies 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, sub–dependencies 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 out–of–date, 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
@@ -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
@@ -1,5 +1,5 @@
|
||||
# -*- coding=utf-8 -*-
|
||||
__version__ = "1.0.1"
|
||||
__version__ = "1.0.5.dev0"
|
||||
|
||||
|
||||
from .exceptions import RequirementError
|
||||
|
||||
+4
-3
@@ -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
@@ -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
@@ -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
@@ -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):
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
@@ -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
@@ -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."')
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
@@ -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.
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
Reference in New Issue
Block a user