diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..d215fe68 --- /dev/null +++ b/.gitattributes @@ -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 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5ad4fcd8..8039c71c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -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 `_ - -- Virtualenv names will now appear in prompts for most Windows users. `#2167 `_ - -- Added support for cmder shell paths with spaces. `#2168 `_ - -- Added nested JSON output to the ``pipenv graph`` command. `#2199 `_ - -- Dropped vendored pip 9 and vendored, patched, and migrated to pip 10. - Updated patched piptools version. `#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 `_ - -- Virtualenv activation lines will now avoid being written to some shell history files. `#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 `_ - -- Added support for mounted drives via UNC paths. `#2331 `_ - -- Added support for Windows Subsystem for Linux bash shell detection. `#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 + `_ + +- Virtualenv names will now appear in prompts for most Windows users. `#2167 + `_ + +- Added support for cmder shell paths with spaces. `#2168 + `_ + +- Added nested JSON output to the ``pipenv graph`` command. `#2199 + `_ + +- Dropped vendored pip 9 and vendored, patched, and migrated to pip 10. Updated + patched piptools version. `#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 + `_ + +- Virtualenv activation lines will now avoid being written to some shell + history files. `#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 `_ + +- Added support for mounted drives via UNC paths. `#2331 + `_ + +- Added support for Windows Subsystem for Linux bash shell detection. `#2363 + `_ + +- Pipenv will now generate hashes much more quickly by resolving them in a + single pass during locking. `#2384 + `_ + +- ``pipenv run`` will now avoid spawning additional ``COMSPEC`` instances to + run commands in when possible. `#2385 + `_ + +- Massive internal improvements to requirements parsing codebase, resolver, and + error messaging. `#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 `_ + 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 `_ + +- 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 `_ - .. 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 `_ - -- 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 `_ - Bug Fixes --------- -- Massive internal improvements to requirements parsing codebase, resolver, and error messaging. `#1962 `_, +- Massive internal improvements to requirements parsing codebase, resolver, and + error messaging. `#1962 `_, `#2186 `_, `#2263 `_, `#2312 `_ - -- Pipenv will now parse & capitalize ``platform_python_implementation`` markers. `#2123 `_ - -- Fixed a bug with parsing and grouping old-style ``setup.py`` extras during resolution `#2142 `_ - -- Fixed a bug causing pipenv graph to throw unhelpful exceptions when running against empty or non-existent environments. `#2161 `_ - -- Fixed a bug which caused ``--system`` to incorrectly abort when users were in a virtualenv. `#2181 `_ - -- Removed vendored ``cacert.pem`` which could cause issues for some users with custom certificate settings. `#2193 `_ - -- Fixed a regression which led to direct invocations of ``virtualenv``, rather than calling it by module. `#2198 `_ - + +- Pipenv will now parse & capitalize ``platform_python_implementation`` + markers. `#2123 `_ + +- Fixed a bug with parsing and grouping old-style ``setup.py`` extras during + resolution `#2142 `_ + +- Fixed a bug causing pipenv graph to throw unhelpful exceptions when running + against empty or non-existent environments. `#2161 + `_ + +- Fixed a bug which caused ``--system`` to incorrectly abort when users were in + a virtualenv. `#2181 `_ + +- Removed vendored ``cacert.pem`` which could cause issues for some users with + custom certificate settings. `#2193 + `_ + +- Fixed a regression which led to direct invocations of ``virtualenv``, rather + than calling it by module. `#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 `_ + 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 `_ + +- ``pipenv clean`` will now correctly ignore comments from ``pip freeze`` when + cleaning the environment. `#2262 + `_ + +- Resolution bugs causing packages for incompatible python versions to be + locked have been fixed. `#2267 + `_ + +- Fixed a bug causing pipenv graph to fail to display sometimes. `#2268 + `_ + +- Updated ``requirementslib`` to fix a bug in pipfile parsing affecting + relative path conversions. `#2269 + `_ + +- Windows executable discovery now leverages ``os.pathext``. `#2298 + `_ + +- Fixed a bug which caused ``--deploy --system`` to inadvertently create a + virtualenv before failing. `#2301 + `_ + +- Fixed an issue which led to a failure to unquote special characters in file + and wheel paths. `#2302 `_ + +- VCS dependencies are now manually obtained only if they do not match the + requested ref. `#2304 `_ + +- Added error handling functionality to properly cope with single-digit + ``Requires-Python`` metatdata with no specifiers. `#2377 + `_ + +- ``pipenv update`` will now always run the resolver and lock before ensuring + your dependencies are in sync with your lockfile. `#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 + `_ + +- Patched ``python-dotenv`` to ensure that environment variables always get + encoded to the filesystem encoding. `#2386 + `_ + + +Improved Documentation +---------------------- + +- Update documentation wording to clarify Pipenv's overall role in the packaging ecosystem. `#2194 `_ -- ``pipenv clean`` will now correctly ignore comments from ``pip freeze`` when cleaning the environment. `#2262 `_ +- Added contribution documentation and guidelines. `#2205 `_ -- Resolution bugs causing packages for incompatible python versions to be locked have been fixed. `#2267 `_ - -- Fixed a bug causing pipenv graph to fail to display sometimes. `#2268 `_ - -- Updated ``requirementslib`` to fix a bug in pipfile parsing affecting relative path conversions. `#2269 `_ - -- Windows executable discovery now leverages ``os.pathext``. `#2298 `_ - -- Fixed a bug which caused ``--deploy --system`` to inadvertently create a virtualenv before failing. `#2301 `_ - -- Fixed an issue which led to a failure to unquote special characters in file and wheel paths. `#2302 `_ - -- VCS dependencies are now manually obtained only if they do not match the requested ref. `#2304 `_ - -- Added error handling functionality to properly cope with single-digit ``Requires-Python`` metatdata with no specifiers. `#2377 `_ - -- ``pipenv update`` will now always run the resolver and lock before ensuring your dependencies are in sync with your lockfile. `#2379 `_ +- Added instructions for supervisord compatibility. `#2215 `_ +- Fixed broken links to development philosophy and contribution documentation. `#2248 `_ + Vendored Libraries ------------------ -- Removed vendored ``cacert.pem`` which could cause issues for some users with custom certificate settings. `#2193 `_ - -- Dropped vendored pip 9 and vendored, patched, and migrated to pip 10. - Updated patched piptools version. `#2255 `_ - -- Updated ``requirementslib`` to fix a bug in pipfile parsing affecting relative path conversions. `#2269 `_ - -- Added custom shell detection library ``shellingham``, a port of our changes to ``pew``. `#2363 `_ - +- Removed vendored ``cacert.pem`` which could cause issues for some users with + custom certificate settings. `#2193 + `_ + +- Dropped vendored pip 9 and vendored, patched, and migrated to pip 10. Updated + patched piptools version. `#2255 + `_ + +- Updated ``requirementslib`` to fix a bug in pipfile parsing affecting + relative path conversions. `#2269 + `_ + +- Added custom shell detection library ``shellingham``, a port of our changes + to ``pew``. `#2363 `_ + +- Patched ``python-dotenv`` to ensure that environment variables always get + encoded to the filesystem encoding. `#2386 + `_ + - Updated vendored libraries. The following vendored libraries were updated: * distlib from version ``0.2.6`` to ``0.2.7``. diff --git a/HISTORY.txt b/HISTORY.txt index 8127c6b0..6f1797a2 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -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. diff --git a/news/1861.feature b/news/1861.feature deleted file mode 100644 index 2af59f0e..00000000 --- a/news/1861.feature +++ /dev/null @@ -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.) diff --git a/news/1962.bugfix b/news/1962.bugfix deleted file mode 100644 index 2286baf7..00000000 --- a/news/1962.bugfix +++ /dev/null @@ -1 +0,0 @@ -Massive internal improvements to requirements parsing codebase, resolver, and error messaging. diff --git a/news/2123.behavior b/news/2123.behavior deleted file mode 100644 index 1afc3ace..00000000 --- a/news/2123.behavior +++ /dev/null @@ -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``). diff --git a/news/2123.bugfix b/news/2123.bugfix deleted file mode 100644 index 6e7aee3d..00000000 --- a/news/2123.bugfix +++ /dev/null @@ -1 +0,0 @@ -Pipenv will now parse & capitalize ``platform_python_implementation`` markers. diff --git a/news/2142.bugfix b/news/2142.bugfix deleted file mode 100644 index 4a215216..00000000 --- a/news/2142.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fixed a bug with parsing and grouping old-style ``setup.py`` extras during resolution diff --git a/news/2161.bugfix b/news/2161.bugfix deleted file mode 100644 index ecab3232..00000000 --- a/news/2161.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fixed a bug causing pipenv graph to throw unhelpful exceptions when running against empty or non-existent environments. diff --git a/news/2167.feature b/news/2167.feature deleted file mode 100644 index 2ce83ecc..00000000 --- a/news/2167.feature +++ /dev/null @@ -1 +0,0 @@ -Virtualenv names will now appear in prompts for most Windows users. diff --git a/news/2168.feature b/news/2168.feature deleted file mode 100644 index ad280b2f..00000000 --- a/news/2168.feature +++ /dev/null @@ -1 +0,0 @@ -Added support for cmder shell paths with spaces. diff --git a/news/2181.bugfix b/news/2181.bugfix deleted file mode 100644 index f72cc260..00000000 --- a/news/2181.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fixed a bug which caused ``--system`` to incorrectly abort when users were in a virtualenv. diff --git a/news/2184.trivial b/news/2184.trivial deleted file mode 100644 index 14ffb69c..00000000 --- a/news/2184.trivial +++ /dev/null @@ -1 +0,0 @@ -Added an invoke task to generate patches against vendored dependencies. diff --git a/news/2186.bugfix b/news/2186.bugfix deleted file mode 100644 index 2286baf7..00000000 --- a/news/2186.bugfix +++ /dev/null @@ -1 +0,0 @@ -Massive internal improvements to requirements parsing codebase, resolver, and error messaging. diff --git a/news/2193.bugfix b/news/2193.bugfix deleted file mode 100644 index 133f8716..00000000 --- a/news/2193.bugfix +++ /dev/null @@ -1 +0,0 @@ -Removed vendored ``cacert.pem`` which could cause issues for some users with custom certificate settings. diff --git a/news/2193.vendor b/news/2193.vendor deleted file mode 100644 index 133f8716..00000000 --- a/news/2193.vendor +++ /dev/null @@ -1 +0,0 @@ -Removed vendored ``cacert.pem`` which could cause issues for some users with custom certificate settings. diff --git a/news/2194.docs b/news/2194.docs deleted file mode 100644 index 9bd3b876..00000000 --- a/news/2194.docs +++ /dev/null @@ -1 +0,0 @@ -Update documentation wording to clarify Pipenv's overall role in the packaging ecosystem. diff --git a/news/2198.bugfix b/news/2198.bugfix deleted file mode 100644 index 78ee0287..00000000 --- a/news/2198.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fixed a regression which led to direct invocations of ``virtualenv``, rather than calling it by module. diff --git a/news/2199.feature b/news/2199.feature deleted file mode 100644 index 32840747..00000000 --- a/news/2199.feature +++ /dev/null @@ -1 +0,0 @@ -Added nested JSON output to the ``pipenv graph`` command. diff --git a/news/2205.docs b/news/2205.docs deleted file mode 100644 index 4c34230c..00000000 --- a/news/2205.docs +++ /dev/null @@ -1 +0,0 @@ -Added contribution documentation and guidelines. diff --git a/news/2209.bugfix b/news/2209.bugfix deleted file mode 100644 index 8496363d..00000000 --- a/news/2209.bugfix +++ /dev/null @@ -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. diff --git a/news/2215.docs b/news/2215.docs deleted file mode 100644 index f2308c26..00000000 --- a/news/2215.docs +++ /dev/null @@ -1 +0,0 @@ -Added instructions for supervisord compatibility. diff --git a/news/2248.docs b/news/2248.docs deleted file mode 100644 index 123a56c4..00000000 --- a/news/2248.docs +++ /dev/null @@ -1 +0,0 @@ -Fixed broken links to development philosophy and contribution documentation. diff --git a/news/2255.feature b/news/2255.feature deleted file mode 100644 index f78ef2c4..00000000 --- a/news/2255.feature +++ /dev/null @@ -1,2 +0,0 @@ -Dropped vendored pip 9 and vendored, patched, and migrated to pip 10. -Updated patched piptools version. diff --git a/news/2255.vendor b/news/2255.vendor deleted file mode 100644 index f78ef2c4..00000000 --- a/news/2255.vendor +++ /dev/null @@ -1,2 +0,0 @@ -Dropped vendored pip 9 and vendored, patched, and migrated to pip 10. -Updated patched piptools version. diff --git a/news/2262.bugfix b/news/2262.bugfix deleted file mode 100644 index 30bc4e98..00000000 --- a/news/2262.bugfix +++ /dev/null @@ -1 +0,0 @@ -``pipenv clean`` will now correctly ignore comments from ``pip freeze`` when cleaning the environment. diff --git a/news/2263.bugfix b/news/2263.bugfix deleted file mode 100644 index 2286baf7..00000000 --- a/news/2263.bugfix +++ /dev/null @@ -1 +0,0 @@ -Massive internal improvements to requirements parsing codebase, resolver, and error messaging. diff --git a/news/2267.bugfix b/news/2267.bugfix deleted file mode 100644 index c0d4ad41..00000000 --- a/news/2267.bugfix +++ /dev/null @@ -1 +0,0 @@ -Resolution bugs causing packages for incompatible python versions to be locked have been fixed. diff --git a/news/2268.bugfix b/news/2268.bugfix deleted file mode 100644 index 307580fa..00000000 --- a/news/2268.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fixed a bug causing pipenv graph to fail to display sometimes. diff --git a/news/2269.bugfix b/news/2269.bugfix deleted file mode 100644 index 223ffda2..00000000 --- a/news/2269.bugfix +++ /dev/null @@ -1 +0,0 @@ -Updated ``requirementslib`` to fix a bug in pipfile parsing affecting relative path conversions. diff --git a/news/2269.vendor b/news/2269.vendor deleted file mode 100644 index 223ffda2..00000000 --- a/news/2269.vendor +++ /dev/null @@ -1 +0,0 @@ -Updated ``requirementslib`` to fix a bug in pipfile parsing affecting relative path conversions. diff --git a/news/2281.feature b/news/2281.feature deleted file mode 100644 index 42f9fb76..00000000 --- a/news/2281.feature +++ /dev/null @@ -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. diff --git a/news/2287.feature b/news/2287.feature deleted file mode 100644 index bea636a7..00000000 --- a/news/2287.feature +++ /dev/null @@ -1 +0,0 @@ -Virtualenv activation lines will now avoid being written to some shell history files. diff --git a/news/2298.bugfix b/news/2298.bugfix deleted file mode 100644 index b6a2709a..00000000 --- a/news/2298.bugfix +++ /dev/null @@ -1 +0,0 @@ -Windows executable discovery now leverages ``os.pathext``. diff --git a/news/2301.bugfix b/news/2301.bugfix deleted file mode 100644 index 0ad1ab5d..00000000 --- a/news/2301.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fixed a bug which caused ``--deploy --system`` to inadvertently create a virtualenv before failing. diff --git a/news/2302.bugfix b/news/2302.bugfix deleted file mode 100644 index 16b1cce2..00000000 --- a/news/2302.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fixed an issue which led to a failure to unquote special characters in file and wheel paths. diff --git a/news/2304.bugfix b/news/2304.bugfix deleted file mode 100644 index 86b9cccf..00000000 --- a/news/2304.bugfix +++ /dev/null @@ -1 +0,0 @@ -VCS dependencies are now manually obtained only if they do not match the requested ref. diff --git a/news/2307.trivial b/news/2307.trivial deleted file mode 100644 index 2db3d023..00000000 --- a/news/2307.trivial +++ /dev/null @@ -1 +0,0 @@ -Change function name of ``pipenv.utils.actually_resolve_reps`` to ``pipenv.utils.actually_resolve_deps``. diff --git a/news/2309.behavior b/news/2309.behavior deleted file mode 100644 index 2650524f..00000000 --- a/news/2309.behavior +++ /dev/null @@ -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. diff --git a/news/2309.feature b/news/2309.feature deleted file mode 100644 index 2650524f..00000000 --- a/news/2309.feature +++ /dev/null @@ -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. diff --git a/news/2311.trivial b/news/2311.trivial deleted file mode 100644 index d23379b0..00000000 --- a/news/2311.trivial +++ /dev/null @@ -1 +0,0 @@ -Removed unnecessary comma from documentation. diff --git a/news/2312.bugfix b/news/2312.bugfix deleted file mode 100644 index 2286baf7..00000000 --- a/news/2312.bugfix +++ /dev/null @@ -1 +0,0 @@ -Massive internal improvements to requirements parsing codebase, resolver, and error messaging. diff --git a/news/2312.trivial b/news/2312.trivial deleted file mode 100644 index baa7508f..00000000 --- a/news/2312.trivial +++ /dev/null @@ -1 +0,0 @@ -Added ``pipenv run`` suggestion for users who are first creating environment. diff --git a/news/2331.feature b/news/2331.feature deleted file mode 100644 index eff70e5e..00000000 --- a/news/2331.feature +++ /dev/null @@ -1 +0,0 @@ -Added support for mounted drives via UNC paths. diff --git a/news/2363.feature b/news/2363.feature deleted file mode 100644 index aee00776..00000000 --- a/news/2363.feature +++ /dev/null @@ -1 +0,0 @@ -Added support for Windows Subsystem for Linux bash shell detection. diff --git a/news/2363.vendor b/news/2363.vendor deleted file mode 100644 index 1ed55bce..00000000 --- a/news/2363.vendor +++ /dev/null @@ -1 +0,0 @@ -Added custom shell detection library ``shellingham``, a port of our changes to ``pew``. diff --git a/news/2368.vendor b/news/2368.vendor deleted file mode 100644 index 295fe842..00000000 --- a/news/2368.vendor +++ /dev/null @@ -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. diff --git a/news/2377.bugfix b/news/2377.bugfix deleted file mode 100644 index 0d81056e..00000000 --- a/news/2377.bugfix +++ /dev/null @@ -1 +0,0 @@ -Added error handling functionality to properly cope with single-digit ``Requires-Python`` metatdata with no specifiers. diff --git a/news/2379.bugfix b/news/2379.bugfix deleted file mode 100644 index 06d678da..00000000 --- a/news/2379.bugfix +++ /dev/null @@ -1 +0,0 @@ -``pipenv update`` will now always run the resolver and lock before ensuring your dependencies are in sync with your lockfile. diff --git a/news/2386.bugfix b/news/2386.bugfix deleted file mode 100644 index ae0e87c7..00000000 --- a/news/2386.bugfix +++ /dev/null @@ -1 +0,0 @@ -Patched ``python-dotenv`` to ensure that environment variables always get encoded to the filesystem encoding. diff --git a/news/2386.vendor b/news/2386.vendor deleted file mode 100644 index ae0e87c7..00000000 --- a/news/2386.vendor +++ /dev/null @@ -1 +0,0 @@ -Patched ``python-dotenv`` to ensure that environment variables always get encoded to the filesystem encoding. diff --git a/news/2388.feature b/news/2388.feature deleted file mode 100644 index 2286baf7..00000000 --- a/news/2388.feature +++ /dev/null @@ -1 +0,0 @@ -Massive internal improvements to requirements parsing codebase, resolver, and error messaging. diff --git a/news/releasing.trivial.rst b/news/releasing.trivial.rst deleted file mode 100644 index b78d0081..00000000 --- a/news/releasing.trivial.rst +++ /dev/null @@ -1 +0,0 @@ -Added release tasks for maintainers. diff --git a/pipenv/__version__.py b/pipenv/__version__.py index c938b87a..5692134d 100644 --- a/pipenv/__version__.py +++ b/pipenv/__version__.py @@ -2,4 +2,4 @@ # // ) ) / / // ) ) //___) ) // ) ) || / / # //___/ / / / //___/ / // // / / || / / # // / / // ((____ // / / ||/ / -__version__ = '2018.6.0.dev0' +__version__ = '2018.6.25' diff --git a/pipenv/cli.py b/pipenv/cli.py index 91abc522..5e7b470b 100644 --- a/pipenv/cli.py +++ b/pipenv/cli.py @@ -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.") diff --git a/pipenv/core.py b/pipenv/core.py index ea56cbe2..2f85ab9c 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -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, ) ) diff --git a/pipenv/patched/piptools/repositories/local.py b/pipenv/patched/piptools/repositories/local.py index 08dabe12..480ad1ed 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/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py index 1c0db571..3fee3d89 100644 --- a/pipenv/patched/piptools/repositories/pypi.py +++ b/pipenv/patched/piptools/repositories/pypi.py @@ -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,=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) diff --git a/pipenv/patched/piptools/utils.py b/pipenv/patched/piptools/utils.py index 1d732bf9..12c3991a 100644 --- a/pipenv/patched/piptools/utils.py +++ b/pipenv/patched/piptools/utils.py @@ -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, 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."') diff --git a/tasks/vendoring/patches/patched/piptools.patch b/tasks/vendoring/patches/patched/piptools.patch index d7f7190d..088aa06c 100644 --- a/tasks/vendoring/patches/patched/piptools.patch +++ b/tasks/vendoring/patches/patched/piptools.patch @@ -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,= 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,