Merge branch 'master' into issue-2747

This commit is contained in:
Dan Ryan
2019-03-11 00:17:15 -04:00
289 changed files with 16341 additions and 5974 deletions
+3 -2
View File
@@ -10,5 +10,6 @@ steps:
- bash: |
export GIT_SSL_CAINFO=$(python -m certifi)
export LANG=C.UTF-8
python -m pip install check-manifest
check-manifest
python -m pip install --upgrade setuptools twine readme_renderer[md]
python setup.py sdist
twine check dist/*
+2 -1
View File
@@ -16,8 +16,9 @@ steps:
export PIP_PROCESS_DEPENDENCY_LINKS="1"
echo "Path $PATH"
echo "Installing Pipenv…"
pip install -e "$(pwd)" --upgrade
pip install -e "$(pwd)[test]" --upgrade
pipenv install --deploy --dev
pipenv run pip install -e "$(pwd)[test]" --upgrade
echo pipenv --venv && echo pipenv --py && echo pipenv run python --version
displayName: Make Virtualenv
+2 -3
View File
@@ -10,9 +10,8 @@ jobs:
maxParallel: 4
matrix:
${{ if eq(parameters.vmImage, 'vs2017-win2016') }}:
# TODO remove once vs2017-win2016 has Python 3.7
Python37:
python.version: '>= 3.7.0-b2'
python.version: '>= 3.7.2'
python.architecture: x64
${{ if ne(parameters.vmImage, 'vs2017-win2016' )}}:
Python37:
@@ -33,7 +32,7 @@ jobs:
pip install certifi
export GIT_SSL_CAINFO=$(python -m certifi)
export LANG=C.UTF-8
python -m pip install --upgrade invoke requests parver
python -m pip install --upgrade invoke requests parver bs4 vistir towncrier pip setuptools wheel --upgrade-strategy=eager
python -m invoke vendoring.update
- template: ./run-manifest-check.yml
+1
View File
@@ -8,6 +8,7 @@ trigger:
exclude:
- docs/*
- news/*
- peeps/*
- README.md
- pipenv/*.txt
- CHANGELOG.rst
+1 -1
View File
@@ -1,6 +1,6 @@
steps:
- script: |
virtualenv D:\.venv
D:\.venv\Scripts\pip.exe install -e . && D:\.venv\Scripts\pipenv install --dev
D:\.venv\Scripts\pip.exe install -e .[test] && D:\.venv\Scripts\pipenv install --dev && D:\.venv\Scripts\pipenv run pip install -e .[test]
echo D:\.venv\Scripts\pipenv --venv && echo D:\.venv\Scripts\pipenv --py && echo D:\.venv\Scripts\pipenv run python --version
displayName: Make Virtualenv
@@ -1,3 +1,3 @@
steps:
- script: 'python -m pip install --upgrade pip && python -m pip install -e .'
- script: 'python -m pip install --upgrade pip && python -m pip install -e .[test]'
displayName: Upgrade Pip & Install Pipenv
+1
View File
@@ -8,6 +8,7 @@ trigger:
exclude:
- docs/*
- news/*
- peeps/*
- README.md
- pipenv/*.txt
- CHANGELOG.rst
+5
View File
@@ -153,3 +153,8 @@ venv.bak/
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
.vs/slnx.sqlite
# mypy/typing section
typeshed/
.dmypy.json
mypyhtml/
+12
View File
@@ -13,3 +13,15 @@
[submodule "tests/test_artifacts/git/dateutil"]
path = tests/test_artifacts/git/dateutil
url = https://github.com/dateutil/dateutil
[submodule "tests/test_artifacts/git/pyinstaller"]
path = tests/test_artifacts/git/pyinstaller
url = https://github.com/pyinstaller/pyinstaller.git
[submodule "tests/test_artifacts/git/jinja2"]
path = tests/test_artifacts/git/jinja2
url = https://github.com/pallets/jinja.git
[submodule "tests/test_artifacts/git/flask"]
path = tests/test_artifacts/git/flask
url = https://github.com/pallets/flask.git
[submodule "tests/test_artifacts/git/requests-2.18.4"]
path = tests/test_artifacts/git/requests-2.18.4
url = https://github.com/requests/requests
-50
View File
@@ -1,50 +0,0 @@
2018.7.1.dev0 (2018-07-15)
==========================
Features & Improvements
-----------------------
- Updated test-pypi addon to better support json-api access (forward compatibility).
Improved testing process for new contributors. `#2568 <https://github.com/pypa/pipenv/issues/2568>`_
Behavior Changes
----------------
- Virtual environment activation for ``run`` is revised to improve interpolation
with other Python discovery tools. `#2503 <https://github.com/pypa/pipenv/issues/2503>`_
- Improve terminal coloring to display better in Powershell. `#2511 <https://github.com/pypa/pipenv/issues/2511>`_
- Invoke ``virtualenv`` directly for virtual environment creation, instead of depending on ``pew``. `#2518 <https://github.com/pypa/pipenv/issues/2518>`_
- ``pipenv --help`` will now include short help descriptions. `#2542 <https://github.com/pypa/pipenv/issues/2542>`_
Bug Fixes
---------
- Fix subshell invocation on Windows for Python 2. `#2515 <https://github.com/pypa/pipenv/issues/2515>`_
- Fixed a bug which sometimes caused pipenv to throw a ``TypeError`` or to run into encoding issues when writing lockfiles on python 2. `#2561 <https://github.com/pypa/pipenv/issues/2561>`_
- Improve quoting logic for ``pipenv run`` so it works better with Windows
built-in commands. `#2563 <https://github.com/pypa/pipenv/issues/2563>`_
- Fixed a bug related to parsing vcs requirements with both extras and subdirectory fragments.
Corrected an issue in the ``requirementslib`` parser which led to some markers being discarded rather than evaluated. `#2564 <https://github.com/pypa/pipenv/issues/2564>`_
Vendored Libraries
------------------
- Pew is no longer vendored. Entry point ``pewtwo``, packages ``pipenv.pew`` and
``pipenv.patched.pew`` are removed. `#2521 <https://github.com/pypa/pipenv/issues/2521>`_
Improved Documentation
----------------------
- Simplified the test configuration process. `#2568 <https://github.com/pypa/pipenv/issues/2568>`_
+136 -101
View File
@@ -1,3 +1,39 @@
2018.11.26 (2018-11-26)
=======================
Bug Fixes
---------
- Environment variables are expanded correctly before running scripts on POSIX. `#3178 <https://github.com/pypa/pipenv/issues/3178>`_
- Pipenv will no longer disable user-mode installation when the ``--system`` flag is passed in. `#3222 <https://github.com/pypa/pipenv/issues/3222>`_
- Fixed an issue with attempting to render unicode output in non-unicode locales. `#3223 <https://github.com/pypa/pipenv/issues/3223>`_
- Fixed a bug which could cause failures to occur when parsing python entries from global pyenv version files. `#3224 <https://github.com/pypa/pipenv/issues/3224>`_
- Fixed an issue which prevented the parsing of named extras sections from certain ``setup.py`` files. `#3230 <https://github.com/pypa/pipenv/issues/3230>`_
- Correctly detect the virtualenv location inside an activated virtualenv. `#3231 <https://github.com/pypa/pipenv/issues/3231>`_
- Fixed a bug which caused spinner frames to be written to stdout during locking operations which could cause redirection pipes to fail. `#3239 <https://github.com/pypa/pipenv/issues/3239>`_
- Fixed a bug that editable pacakges can't be uninstalled correctly. `#3240 <https://github.com/pypa/pipenv/issues/3240>`_
- Corrected an issue with installation timeouts which caused dependency resolution to fail for longer duration resolution steps. `#3244 <https://github.com/pypa/pipenv/issues/3244>`_
- Adding normal pep 508 compatible markers is now fully functional when using VCS dependencies. `#3249 <https://github.com/pypa/pipenv/issues/3249>`_
- Updated ``requirementslib`` and ``pythonfinder`` for multiple bugfixes. `#3254 <https://github.com/pypa/pipenv/issues/3254>`_
- Pipenv will now ignore hashes when installing with ``--skip-lock``. `#3255 <https://github.com/pypa/pipenv/issues/3255>`_
- Fixed an issue where pipenv could crash when multiple pipenv processes attempted to create the same directory. `#3257 <https://github.com/pypa/pipenv/issues/3257>`_
- Fixed an issue which sometimes prevented successful creation of project pipfiles. `#3260 <https://github.com/pypa/pipenv/issues/3260>`_
- ``pipenv install`` will now unset the ``PYTHONHOME`` environment variable when not combined with ``--system``. `#3261 <https://github.com/pypa/pipenv/issues/3261>`_
- Pipenv will ensure that warnings do not interfere with the resolution process by suppressing warnings' usage of standard output and writing to standard error instead. `#3273 <https://github.com/pypa/pipenv/issues/3273>`_
- Fixed an issue which prevented variables from the environment, such as ``PIPENV_DEV`` or ``PIPENV_SYSTEM``, from being parsed and implemented correctly. `#3278 <https://github.com/pypa/pipenv/issues/3278>`_
- Clear pythonfinder cache after Python install. `#3287 <https://github.com/pypa/pipenv/issues/3287>`_
- Fixed a race condition in hash resolution for dependencies for certain dependencies with missing cache entries or fresh Pipenv installs. `#3289 <https://github.com/pypa/pipenv/issues/3289>`_
- Pipenv will now respect top-level pins over VCS dependency locks. `#3296 <https://github.com/pypa/pipenv/issues/3296>`_
Vendored Libraries
------------------
- Update vendored dependencies to resolve resolution output parsing and python finding:
- ``pythonfinder 1.1.9 -> 1.1.10``
- ``requirementslib 1.3.1 -> 1.3.3``
- ``vistir 0.2.3 -> 0.2.5`` `#3280 <https://github.com/pypa/pipenv/issues/3280>`_
2018.11.14 (2018-11-14)
=======================
@@ -91,33 +127,33 @@ Bug Fixes
---------
- Fixed a bug in ``pipenv clean`` which caused global packages to sometimes be inadvertently targeted for cleanup. `#2849 <https://github.com/pypa/pipenv/issues/2849>`_
- Fix broken backport imports for vendored vistir. `#2950 <https://github.com/pypa/pipenv/issues/2950>`_,
`#2955 <https://github.com/pypa/pipenv/issues/2955>`_,
`#2961 <https://github.com/pypa/pipenv/issues/2961>`_
- Fixed a bug with importing local vendored dependencies when running ``pipenv graph``. `#2952 <https://github.com/pypa/pipenv/issues/2952>`_
- Fixed a bug which caused executable discovery to fail when running inside a virtualenv. `#2957 <https://github.com/pypa/pipenv/issues/2957>`_
- Fix parsing of outline tables. `#2971 <https://github.com/pypa/pipenv/issues/2971>`_
- Fixed a bug which caused ``verify_ssl`` to fail to drop through to ``pip install`` correctly as ``trusted-host``. `#2979 <https://github.com/pypa/pipenv/issues/2979>`_
- Fixed a bug which caused canonicalized package names to fail to resolve against PyPI. `#2989 <https://github.com/pypa/pipenv/issues/2989>`_
- Enhanced CI detection to detect Azure Devops builds. `#2993 <https://github.com/pypa/pipenv/issues/2993>`_
- Fixed a bug which prevented installing pinned versions which used redirection symbols from the command line. `#2998 <https://github.com/pypa/pipenv/issues/2998>`_
- Fixed a bug which prevented installing the local directory in non-editable mode. `#3005 <https://github.com/pypa/pipenv/issues/3005>`_
Vendored Libraries
------------------
- Updated ``requirementslib`` to version ``1.1.9``. `#2989 <https://github.com/pypa/pipenv/issues/2989>`_
- Upgraded ``pythonfinder => 1.1.1`` and ``vistir => 0.1.7``. `#3007 <https://github.com/pypa/pipenv/issues/3007>`_
@@ -129,55 +165,55 @@ Features & Improvements
- Added environment variables `PIPENV_VERBOSE` and `PIPENV_QUIET` to control
output verbosity without needing to pass options. `#2527 <https://github.com/pypa/pipenv/issues/2527>`_
- Updated test-pypi addon to better support json-api access (forward compatibility).
Improved testing process for new contributors. `#2568 <https://github.com/pypa/pipenv/issues/2568>`_
- Greatly enhanced python discovery functionality:
- Added pep514 (windows launcher/finder) support for python discovery.
- Introduced architecture discovery for python installations which support different architectures. `#2582 <https://github.com/pypa/pipenv/issues/2582>`_
- Added support for ``pipenv shell`` on msys and cygwin/mingw/git bash for Windows. `#2641 <https://github.com/pypa/pipenv/issues/2641>`_
- Enhanced resolution of editable and VCS dependencies. `#2643 <https://github.com/pypa/pipenv/issues/2643>`_
- Deduplicate and refactor CLI to use stateful arguments and object passing. See `this issue <https://github.com/pallets/click/issues/108>`_ for reference. `#2814 <https://github.com/pypa/pipenv/issues/2814>`_
Behavior Changes
----------------
- Virtual environment activation for ``run`` is revised to improve interpolation
with other Python discovery tools. `#2503 <https://github.com/pypa/pipenv/issues/2503>`_
- Improve terminal coloring to display better in Powershell. `#2511 <https://github.com/pypa/pipenv/issues/2511>`_
- Invoke ``virtualenv`` directly for virtual environment creation, instead of depending on ``pew``. `#2518 <https://github.com/pypa/pipenv/issues/2518>`_
- ``pipenv --help`` will now include short help descriptions. `#2542 <https://github.com/pypa/pipenv/issues/2542>`_
- Add ``COMSPEC`` to fallback option (along with ``SHELL`` and ``PYENV_SHELL``)
if shell detection fails, improving robustness on Windows. `#2651 <https://github.com/pypa/pipenv/issues/2651>`_
- Fallback to shell mode if `run` fails with Windows error 193 to handle non-executable commands. This should improve usability on Windows, where some users run non-executable files without specifying a command, relying on Windows file association to choose the current command. `#2718 <https://github.com/pypa/pipenv/issues/2718>`_
Bug Fixes
---------
- Fixed a bug which prevented installation of editable requirements using ``ssh://`` style urls `#1393 <https://github.com/pypa/pipenv/issues/1393>`_
- VCS Refs for locked local editable dependencies will now update appropriately to the latest hash when running ``pipenv update``. `#1690 <https://github.com/pypa/pipenv/issues/1690>`_
- ``.tar.gz`` and ``.zip`` artifacts will now have dependencies installed even when they are missing from the lockfile. `#2173 <https://github.com/pypa/pipenv/issues/2173>`_
- The command line parser will now handle multiple ``-e/--editable`` dependencies properly via click's option parser to help mitigate future parsing issues. `#2279 <https://github.com/pypa/pipenv/issues/2279>`_
- Fixed the ability of pipenv to parse ``dependency_links`` from ``setup.py`` when ``PIP_PROCESS_DEPENDENCY_LINKS`` is enabled. `#2434 <https://github.com/pypa/pipenv/issues/2434>`_
- Fixed a bug which could cause ``-i/--index`` arguments to sometimes be incorrectly picked up in packages. This is now handled in the command line parser. `#2494 <https://github.com/pypa/pipenv/issues/2494>`_
- Fixed non-deterministic resolution issues related to changes to the internal package finder in ``pip 10``. `#2499 <https://github.com/pypa/pipenv/issues/2499>`_,
`#2529 <https://github.com/pypa/pipenv/issues/2529>`_,
`#2589 <https://github.com/pypa/pipenv/issues/2589>`_,
@@ -191,51 +227,51 @@ Bug Fixes
`#2879 <https://github.com/pypa/pipenv/issues/2879>`_,
`#2894 <https://github.com/pypa/pipenv/issues/2894>`_,
`#2933 <https://github.com/pypa/pipenv/issues/2933>`_
- Fix subshell invocation on Windows for Python 2. `#2515 <https://github.com/pypa/pipenv/issues/2515>`_
- Fixed a bug which sometimes caused pipenv to throw a ``TypeError`` or to run into encoding issues when writing lockfiles on python 2. `#2561 <https://github.com/pypa/pipenv/issues/2561>`_
- Improve quoting logic for ``pipenv run`` so it works better with Windows
built-in commands. `#2563 <https://github.com/pypa/pipenv/issues/2563>`_
- Fixed a bug related to parsing vcs requirements with both extras and subdirectory fragments.
Corrected an issue in the ``requirementslib`` parser which led to some markers being discarded rather than evaluated. `#2564 <https://github.com/pypa/pipenv/issues/2564>`_
- Fixed multiple issues with finding the correct system python locations. `#2582 <https://github.com/pypa/pipenv/issues/2582>`_
- Catch JSON decoding error to prevent exception when the lock file is of
invalid format. `#2607 <https://github.com/pypa/pipenv/issues/2607>`_
- Fixed a rare bug which could sometimes cause errors when installing packages with custom sources. `#2610 <https://github.com/pypa/pipenv/issues/2610>`_
- Update requirementslib to fix a bug which could raise an ``UnboundLocalError`` when parsing malformed VCS URIs. `#2617 <https://github.com/pypa/pipenv/issues/2617>`_
- Fixed an issue which prevented passing multiple ``--ignore`` parameters to ``pipenv check``. `#2632 <https://github.com/pypa/pipenv/issues/2632>`_
- Fixed a bug which caused attempted hashing of ``ssh://`` style URIs which could cause failures during installation of private ssh repositories.
- Corrected path conversion issues which caused certain editable VCS paths to be converted to ``ssh://`` URIs improperly. `#2639 <https://github.com/pypa/pipenv/issues/2639>`_
- Fixed a bug which caused paths to be formatted incorrectly when using ``pipenv shell`` in bash for windows. `#2641 <https://github.com/pypa/pipenv/issues/2641>`_
- Dependency links to private repositories defined via ``ssh://`` schemes will now install correctly and skip hashing as long as ``PIP_PROCESS_DEPENDENCY_LINKS=1``. `#2643 <https://github.com/pypa/pipenv/issues/2643>`_
- Fixed a bug which sometimes caused pipenv to parse the ``trusted_host`` argument to pip incorrectly when parsing source URLs which specify ``verify_ssl = false``. `#2656 <https://github.com/pypa/pipenv/issues/2656>`_
- Prevent crashing when a virtual environment in ``WORKON_HOME`` is faulty. `#2676 <https://github.com/pypa/pipenv/issues/2676>`_
- Fixed virtualenv creation failure when a .venv file is present in the project root. `#2680 <https://github.com/pypa/pipenv/issues/2680>`_
- Fixed a bug which could cause the ``-e/--editable`` argument on a dependency to be accidentally parsed as a dependency itself. `#2714 <https://github.com/pypa/pipenv/issues/2714>`_
- Correctly pass `verbose` and `debug` flags to the resolver subprocess so it generates appropriate output. This also resolves a bug introduced by the fix to #2527. `#2732 <https://github.com/pypa/pipenv/issues/2732>`_
- All markers are now included in ``pipenv lock --requirements`` output. `#2748 <https://github.com/pypa/pipenv/issues/2748>`_
- Fixed a bug in marker resolution which could cause duplicate and non-deterministic markers. `#2760 <https://github.com/pypa/pipenv/issues/2760>`_
- Fixed a bug in the dependency resolver which caused regular issues when handling ``setup.py`` based dependency resolution. `#2766 <https://github.com/pypa/pipenv/issues/2766>`_
- Updated vendored dependencies:
- ``pip-tools`` (updated and patched to latest w/ ``pip 18.0`` compatibilty)
- ``pip 10.0.1 => 18.0``
@@ -257,24 +293,24 @@ Bug Fixes
- ``vistir 0.1.4 => 0.1.6`` `#2802 <https://github.com/pypa/pipenv/issues/2802>`_,
`#2867 <https://github.com/pypa/pipenv/issues/2867>`_,
`#2880 <https://github.com/pypa/pipenv/issues/2880>`_
- Fixed a bug where `pipenv` crashes when the `WORKON_HOME` directory does not exist. `#2877 <https://github.com/pypa/pipenv/issues/2877>`_
- Fixed pip is not loaded from pipenv's patched one but the system one `#2912 <https://github.com/pypa/pipenv/issues/2912>`_
- Fixed various bugs related to ``pip 18.1`` release which prevented locking, installation, and syncing, and dumping to a ``requirements.txt`` file. `#2924 <https://github.com/pypa/pipenv/issues/2924>`_
Vendored Libraries
------------------
- Pew is no longer vendored. Entry point ``pewtwo``, packages ``pipenv.pew`` and
``pipenv.patched.pew`` are removed. `#2521 <https://github.com/pypa/pipenv/issues/2521>`_
- Update ``pythonfinder`` to major release ``1.0.0`` for integration. `#2582 <https://github.com/pypa/pipenv/issues/2582>`_
- Update requirementslib to fix a bug which could raise an ``UnboundLocalError`` when parsing malformed VCS URIs. `#2617 <https://github.com/pypa/pipenv/issues/2617>`_
- - Vendored new libraries ``vistir`` and ``pip-shims``, ``tomlkit``, ``modutil``, and ``plette``.
- Update vendored libraries:
@@ -289,7 +325,7 @@ Vendored Libraries
- ``pythonfinder`` to ``1.0.2``
- ``pipdeptree`` to ``0.13.0``
- ``python-dotenv`` to ``0.9.1`` `#2639 <https://github.com/pypa/pipenv/issues/2639>`_
- Updated vendored dependencies:
- ``pip-tools`` (updated and patched to latest w/ ``pip 18.0`` compatibilty)
- ``pip 10.0.1 => 18.0``
@@ -310,31 +346,31 @@ Vendored Libraries
- ``tomlkit 0.4.2 => 0.4.4``
- ``vistir 0.1.4 => 0.1.6`` `#2902 <https://github.com/pypa/pipenv/issues/2902>`_,
`#2935 <https://github.com/pypa/pipenv/issues/2935>`_
Improved Documentation
----------------------
- Simplified the test configuration process. `#2568 <https://github.com/pypa/pipenv/issues/2568>`_
- Updated documentation to use working fortune cookie addon. `#2644 <https://github.com/pypa/pipenv/issues/2644>`_
- Added additional information about troubleshooting ``pipenv shell`` by using the the ``$PIPENV_SHELL`` environment variable. `#2671 <https://github.com/pypa/pipenv/issues/2671>`_
- Added a link to ``PEP-440`` version specifiers in the documentation for additional detail. `#2674 <https://github.com/pypa/pipenv/issues/2674>`_
- Added simple example to README.md for installing from git. `#2685 <https://github.com/pypa/pipenv/issues/2685>`_
- Stopped recommending `--system` for Docker contexts. `#2762 <https://github.com/pypa/pipenv/issues/2762>`_
- Fixed the example url for doing "pipenv install -e
some-repo-url#egg=something", it was missing the "egg=" in the fragment
identifier. `#2792 <https://github.com/pypa/pipenv/issues/2792>`_
- Fixed link to the "be cordial" essay in the contribution documentation. `#2793 <https://github.com/pypa/pipenv/issues/2793>`_
- Clarify `pipenv install` documentation `#2844 <https://github.com/pypa/pipenv/issues/2844>`_
- Replace reference to uservoice with PEEP-000 `#2909 <https://github.com/pypa/pipenv/issues/2909>`_
@@ -345,73 +381,73 @@ Features & Improvements
-----------------------
- All calls to ``pipenv shell`` are now implemented from the ground up using `shellingham <https://github.com/sarugaku/shellingham>`_, a custom library which was purpose built to handle edge cases and shell detection. `#2371 <https://github.com/pypa/pipenv/issues/2371>`_
- Added support for python 3.7 via a few small compatibility / bugfixes. `#2427 <https://github.com/pypa/pipenv/issues/2427>`_,
`#2434 <https://github.com/pypa/pipenv/issues/2434>`_,
`#2436 <https://github.com/pypa/pipenv/issues/2436>`_
- Added new flag ``pipenv --support`` to replace the diagnostic command ``python -m pipenv.help``. `#2477 <https://github.com/pypa/pipenv/issues/2477>`_,
`#2478 <https://github.com/pypa/pipenv/issues/2478>`_
- Improved import times and CLI runtimes with minor tweaks. `#2485 <https://github.com/pypa/pipenv/issues/2485>`_
Bug Fixes
---------
- Fixed an ongoing bug which sometimes resolved incompatible versions into lockfiles. `#1901 <https://github.com/pypa/pipenv/issues/1901>`_
- Fixed a bug which caused errors when creating virtualenvs which contained leading dash characters. `#2415 <https://github.com/pypa/pipenv/issues/2415>`_
- Fixed a logic error which caused ``--deploy --system`` to overwrite editable vcs packages in the pipfile before installing, which caused any installation to fail by default. `#2417 <https://github.com/pypa/pipenv/issues/2417>`_
- Updated requirementslib to fix an issue with properly quoting markers in VCS requirements. `#2419 <https://github.com/pypa/pipenv/issues/2419>`_
- Installed new vendored jinja2 templates for ``click-completion`` which were causing template errors for users with completion enabled. `#2422 <https://github.com/pypa/pipenv/issues/2422>`_
- Added support for python 3.7 via a few small compatibility / bugfixes. `#2427 <https://github.com/pypa/pipenv/issues/2427>`_
- Fixed an issue reading package names from ``setup.py`` files in projects which imported utilities such as ``versioneer``. `#2433 <https://github.com/pypa/pipenv/issues/2433>`_
- Pipenv will now ensure that its internal package names registry files are written with unicode strings. `#2450 <https://github.com/pypa/pipenv/issues/2450>`_
- Fixed a bug causing requirements input as relative paths to be output as absolute paths or URIs.
Fixed a bug affecting normalization of ``git+git@host`` uris. `#2453 <https://github.com/pypa/pipenv/issues/2453>`_
- Pipenv will now always use ``pathlib2`` for ``Path`` based filesystem interactions by default on ``python<3.5``. `#2454 <https://github.com/pypa/pipenv/issues/2454>`_
- Fixed a bug which prevented passing proxy PyPI indexes set with ``--pypi-mirror`` from being passed to pip during virtualenv creation, which could cause the creation to freeze in some cases. `#2462 <https://github.com/pypa/pipenv/issues/2462>`_
- Using the ``python -m pipenv.help`` command will now use proper encoding for the host filesystem to avoid encoding issues. `#2466 <https://github.com/pypa/pipenv/issues/2466>`_
- The new ``jinja2`` templates for ``click_completion`` will now be included in pipenv source distributions. `#2479 <https://github.com/pypa/pipenv/issues/2479>`_
- Resolved a long-standing issue with re-using previously generated ``InstallRequirement`` objects for resolution which could cause ``PKG-INFO`` file information to be deleted, raising a ``TypeError``. `#2480 <https://github.com/pypa/pipenv/issues/2480>`_
- Resolved an issue parsing usernames from private PyPI URIs in ``Pipfiles`` by updating ``requirementslib``. `#2484 <https://github.com/pypa/pipenv/issues/2484>`_
Vendored Libraries
------------------
- All calls to ``pipenv shell`` are now implemented from the ground up using `shellingham <https://github.com/sarugaku/shellingham>`_, a custom library which was purpose built to handle edge cases and shell detection. `#2371 <https://github.com/pypa/pipenv/issues/2371>`_
- Updated requirementslib to fix an issue with properly quoting markers in VCS requirements. `#2419 <https://github.com/pypa/pipenv/issues/2419>`_
- Installed new vendored jinja2 templates for ``click-completion`` which were causing template errors for users with completion enabled. `#2422 <https://github.com/pypa/pipenv/issues/2422>`_
- Add patch to ``prettytoml`` to support Python 3.7. `#2426 <https://github.com/pypa/pipenv/issues/2426>`_
- Patched ``prettytoml.AbstractTable._enumerate_items`` to handle ``StopIteration`` errors in preparation of release of python 3.7. `#2427 <https://github.com/pypa/pipenv/issues/2427>`_
- Fixed an issue reading package names from ``setup.py`` files in projects which imported utilities such as ``versioneer``. `#2433 <https://github.com/pypa/pipenv/issues/2433>`_
- Updated ``requirementslib`` to version ``1.0.9`` `#2453 <https://github.com/pypa/pipenv/issues/2453>`_
- Unraveled a lot of old, unnecessary patches to ``pip-tools`` which were causing non-deterministic resolution errors. `#2480 <https://github.com/pypa/pipenv/issues/2480>`_
- Resolved an issue parsing usernames from private PyPI URIs in ``Pipfiles`` by updating ``requirementslib``. `#2484 <https://github.com/pypa/pipenv/issues/2484>`_
Improved Documentation
----------------------
@@ -576,11 +612,11 @@ Improved Documentation
----------------------
- Update documentation wording to clarify Pipenv's overall role in the packaging ecosystem. `#2194 <https://github.com/pypa/pipenv/issues/2194>`_
- Added contribution documentation and guidelines. `#2205 <https://github.com/pypa/pipenv/issues/2205>`_
- 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>`_
@@ -618,7 +654,6 @@ Vendored Libraries
* 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``.
* 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. `#2368 <https://github.com/pypa/pipenv/issues/2368>`_
+3 -7
View File
@@ -1,16 +1,11 @@
[dev-packages]
pipenv = {path = ".", editable = true}
pipenv = {path = ".", editable = true, extras = ["test"]}
"flake8" = ">=3.3.0,<4"
pytest = "*"
mock = "*"
sphinx = "<=1.5.5"
twine = "*"
sphinx-click = "*"
pytest-xdist = "*"
click = "*"
pytest-pypy = {path = "./tests/pytest-pypi", editable = true}
pytest-tap = "*"
flaky = "*"
pytest-pypi = {path = "./tests/pytest-pypi", editable = true}
stdeb = {version="*", markers="sys_platform == 'linux'"}
black = {version="*", markers="python_version >= '3.6'"}
pytz = "*"
@@ -21,6 +16,7 @@ jedi = "*"
isort = "*"
rope = "*"
passa = {editable = true, git = "https://github.com/sarugaku/passa.git"}
bs4 = "*"
[packages]
Generated
+226 -231
View File
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "6acc712d82698e574727d19b22d05bf46565ecaa414e288fd0d79e385f8fdd10"
"sha256": "d7119fe8fa7be8224ff46509352efbd76dd17accf6a57580dbaf5762e613468b"
},
"pipfile-spec": 6,
"requires": {},
@@ -36,14 +36,6 @@
],
"version": "==1.4.3"
},
"argparse": {
"hashes": [
"sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4",
"sha256:c31647edb69fd3d465a847ea3157d37bed1f95f19760b11a47aa91c04b666314"
],
"markers": "python_version == '2.6'",
"version": "==1.4.0"
},
"arpeggio": {
"hashes": [
"sha256:a5258b84f76661d558492fa87e42db634df143685a0e51802d59cae7daad8732",
@@ -53,10 +45,10 @@
},
"atomicwrites": {
"hashes": [
"sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0",
"sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee"
"sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4",
"sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"
],
"version": "==1.2.1"
"version": "==1.3.0"
},
"attrs": {
"hashes": [
@@ -72,6 +64,38 @@
],
"version": "==2.6.0"
},
"backports.functools-lru-cache": {
"hashes": [
"sha256:9d98697f088eb1b0fa451391f91afb5e3ebde16bbdb272819fd091151fda4f1a",
"sha256:f0b0e4eba956de51238e17573b7087e852dfe9854afd2e9c873f73fc0ca0a6dd"
],
"markers": "python_version < '3'",
"version": "==1.5"
},
"backports.shutil-get-terminal-size": {
"hashes": [
"sha256:0975ba55054c15e346944b38956a4c9cbee9009391e41b86c68990effb8c1f64",
"sha256:713e7a8228ae80341c70586d1cc0a8caa5207346927e23d09dcbcaf18eadec80"
],
"markers": "python_version < '3.3'",
"version": "==1.0.0"
},
"backports.weakref": {
"hashes": [
"sha256:81bc9b51c0abc58edc76aefbbc68c62a787918ffe943a37947e162c3f8e19e82",
"sha256:bc4170a29915f8b22c9e7c4939701859650f2eb84184aee80da329ac0b9825c2"
],
"markers": "python_version < '3.3'",
"version": "==1.0.post1"
},
"beautifulsoup4": {
"hashes": [
"sha256:034740f6cb549b4e932ae1ab975581e6103ac8f942200a0e9759065984391858",
"sha256:945065979fb8529dd2f37dbb58f00b661bdbcbebf954f93b32fdf5263ef35348",
"sha256:ba6d5c59906a85ac23dadfe5c88deaf3e179ef565f4898671253e50a78680718"
],
"version": "==4.7.1"
},
"black": {
"hashes": [
"sha256:817243426042db1d36617910df579a54f1afd659adb96fc5032fcf4b36209739",
@@ -83,10 +107,17 @@
},
"bleach": {
"hashes": [
"sha256:48d39675b80a75f6d1c3bdbffec791cf0bbbab665cf01e20da701c77de278718",
"sha256:73d26f018af5d5adcdabf5c1c974add4361a9c76af215fe32fdec8a6fc5fb9b9"
"sha256:213336e49e102af26d9cde77dd2d0397afabc5a6bf2fed985dc35b5d1e285a16",
"sha256:3fdf7f77adcf649c9911387df51254b813185e32b2c6619f690b593a617e19fa"
],
"version": "==3.0.2"
"version": "==3.1.0"
},
"bs4": {
"hashes": [
"sha256:36ecea1fd7cc5c0c6e4a1ff075df26d50da647b75376626cc186e2212886dd3a"
],
"index": "pypi",
"version": "==0.0.1"
},
"cerberus": {
"hashes": [
@@ -96,47 +127,10 @@
},
"certifi": {
"hashes": [
"sha256:339dc09518b07e2fa7eda5450740925974815557727d6bd35d319c1524a04a4c",
"sha256:6d58c986d22b038c8c0df30d639f23a3e6d172a05c3583e766f4c0b785c0986a"
"sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7",
"sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033"
],
"version": "==2018.10.15"
},
"cffi": {
"hashes": [
"sha256:151b7eefd035c56b2b2e1eb9963c90c6302dc15fbd8c1c0a83a163ff2c7d7743",
"sha256:1553d1e99f035ace1c0544050622b7bc963374a00c467edafac50ad7bd276aef",
"sha256:1b0493c091a1898f1136e3f4f991a784437fac3673780ff9de3bcf46c80b6b50",
"sha256:2ba8a45822b7aee805ab49abfe7eec16b90587f7f26df20c71dd89e45a97076f",
"sha256:3bb6bd7266598f318063e584378b8e27c67de998a43362e8fce664c54ee52d30",
"sha256:3c85641778460581c42924384f5e68076d724ceac0f267d66c757f7535069c93",
"sha256:3eb6434197633b7748cea30bf0ba9f66727cdce45117a712b29a443943733257",
"sha256:495c5c2d43bf6cebe0178eb3e88f9c4aa48d8934aa6e3cddb865c058da76756b",
"sha256:4c91af6e967c2015729d3e69c2e51d92f9898c330d6a851bf8f121236f3defd3",
"sha256:57b2533356cb2d8fac1555815929f7f5f14d68ac77b085d2326b571310f34f6e",
"sha256:770f3782b31f50b68627e22f91cb182c48c47c02eb405fd689472aa7b7aa16dc",
"sha256:79f9b6f7c46ae1f8ded75f68cf8ad50e5729ed4d590c74840471fc2823457d04",
"sha256:7a33145e04d44ce95bcd71e522b478d282ad0eafaf34fe1ec5bbd73e662f22b6",
"sha256:857959354ae3a6fa3da6651b966d13b0a8bed6bbc87a0de7b38a549db1d2a359",
"sha256:87f37fe5130574ff76c17cab61e7d2538a16f843bb7bca8ebbc4b12de3078596",
"sha256:95d5251e4b5ca00061f9d9f3d6fe537247e145a8524ae9fd30a2f8fbce993b5b",
"sha256:9d1d3e63a4afdc29bd76ce6aa9d58c771cd1599fbba8cf5057e7860b203710dd",
"sha256:a36c5c154f9d42ec176e6e620cb0dd275744aa1d804786a71ac37dc3661a5e95",
"sha256:a6a5cb8809091ec9ac03edde9304b3ad82ad4466333432b16d78ef40e0cce0d5",
"sha256:ae5e35a2c189d397b91034642cb0eab0e346f776ec2eb44a49a459e6615d6e2e",
"sha256:b0f7d4a3df8f06cf49f9f121bead236e328074de6449866515cea4907bbc63d6",
"sha256:b75110fb114fa366b29a027d0c9be3709579602ae111ff61674d28c93606acca",
"sha256:ba5e697569f84b13640c9e193170e89c13c6244c24400fc57e88724ef610cd31",
"sha256:be2a9b390f77fd7676d80bc3cdc4f8edb940d8c198ed2d8c0be1319018c778e1",
"sha256:ca1bd81f40adc59011f58159e4aa6445fc585a32bb8ac9badf7a2c1aa23822f2",
"sha256:d5d8555d9bfc3f02385c1c37e9f998e2011f0db4f90e250e5bc0c0a85a813085",
"sha256:e55e22ac0a30023426564b1059b035973ec82186ddddbac867078435801c7801",
"sha256:e90f17980e6ab0f3c2f3730e56d1fe9bcba1891eeea58966e89d352492cc74f4",
"sha256:ecbb7b01409e9b782df5ded849c178a0aa7c906cf8c5a67368047daab282b184",
"sha256:ed01918d545a38998bfa5902c7c00e0fee90e957ce036a4000a88e3fe2264917",
"sha256:edabd457cd23a02965166026fd9bfd196f4324fe6032e866d0f3bd0301cd486f",
"sha256:fdf1c1dc5bafc32bc5d08b054f94d659422b05aba244d6be4ddc1c72d9aa70fb"
],
"version": "==1.11.5"
"version": "==2018.11.29"
},
"chardet": {
"hashes": [
@@ -153,58 +147,27 @@
"index": "pypi",
"version": "==7.0"
},
"cmarkgfm": {
"hashes": [
"sha256:0186dccca79483e3405217993b83b914ba4559fe9a8396efc4eea56561b74061",
"sha256:1a625afc6f62da428df96ec325dc30866cc5781520cbd904ff4ec44cf018171c",
"sha256:207b7673ff4e177374c572feeae0e4ef33be620ec9171c08fd22e2b796e03e3d",
"sha256:275905bb371a99285c74931700db3f0c078e7603bed383e8cf1a09f3ee05a3de",
"sha256:50098f1c4950722521f0671e54139e0edc1837d63c990cf0f3d2c49607bb51a2",
"sha256:50ed116d0b60a07df0dc7b180c28569064b9d37d1578d4c9021cff04d725cb63",
"sha256:61a72def110eed903cd1848245897bcb80d295cd9d13944d4f9f30cba5b76655",
"sha256:64186fb75d973a06df0e6ea12879533b71f6e7ba1ab01ffee7fc3e7534758889",
"sha256:665303d34d7f14f10d7b0651082f25ebf7107f29ef3d699490cac16cdc0fc8ce",
"sha256:70b18f843aec58e4e64aadce48a897fe7c50426718b7753aaee399e72df64190",
"sha256:761ee7b04d1caee2931344ac6bfebf37102ffb203b136b676b0a71a3f0ea3c87",
"sha256:811527e9b7280b136734ed6cb6845e5fbccaeaa132ddf45f0246cbe544016957",
"sha256:987b0e157f70c72a84f3c2f9ef2d7ab0f26c08f2bf326c12c087ff9eebcb3ff5",
"sha256:9fc6a2183d0a9b0974ec7cdcdad42bd78a3be674cc3e65f87dd694419b3b0ab7",
"sha256:a3d17ee4ae739fe16f7501a52255c2e287ac817cfd88565b9859f70520afffea",
"sha256:ba5b5488719c0f2ced0aa1986376f7baff1a1653a8eb5fdfcf3f84c7ce46ef8d",
"sha256:c573ea89dd95d41b6d8cf36799c34b6d5b1eac4aed0212dee0f0a11fb7b01e8f",
"sha256:c5f1b9e8592d2c448c44e6bc0d91224b16ea5f8293908b1561de1f6d2d0658b1",
"sha256:cbe581456357d8f0674d6a590b1aaf46c11d01dd0a23af147a51a798c3818034",
"sha256:cf219bec69e601fe27e3974b7307d2f06082ab385d42752738ad2eb630a47d65",
"sha256:cf5014eb214d814a83a7a47407272d5db10b719dbeaf4d3cfe5969309d0fcf4b",
"sha256:d08bad67fa18f7e8ff738c090628ee0cbf0505d74a991c848d6d04abfe67b697",
"sha256:d6f716d7b1182bf35862b5065112f933f43dd1aa4f8097c9bcfb246f71528a34",
"sha256:e08e479102627641c7cb4ece421c6ed4124820b1758765db32201136762282d9",
"sha256:e20ac21418af0298437d29599f7851915497ce9f2866bc8e86b084d8911ee061",
"sha256:e25f53c37e319241b9a412382140dffac98ca756ba8f360ac7ab5e30cad9670a",
"sha256:e8932bddf159064f04e946fbb64693753488de21586f20e840b3be51745c8c09",
"sha256:f20900f16377f2109783ae9348d34bc80530808439591c3d3df73d5c7ef1a00c"
],
"version": "==0.4.2"
},
"colorama": {
"hashes": [
"sha256:a3d89af5db9e9806a779a50296b5fdb466e281147c2c235e8225ecc6dbf7bbf3",
"sha256:c9b54bebe91a6a803e0772c8561d53f2926bfeb17cd141fbabcb08424086595c"
"sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d",
"sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"
],
"version": "==0.4.0"
"version": "==0.4.1"
},
"configparser": {
"hashes": [
"sha256:5308b47021bc2340965c371f0f058cc6971a04502638d4244225c49d80db273a"
"sha256:5bd5fa2a491dc3cfe920a3f2a107510d65eceae10e9c6e547b90261a4710df32",
"sha256:c114ff90ee2e762db972fa205f02491b1f5cf3ff950decd8542c62970c9bedac",
"sha256:df28e045fbff307a28795b18df6ac8662be3219435560ddb068c283afab1ea7a"
],
"markers": "python_version < '3.2'",
"version": "==3.5.0"
"version": "==3.7.1"
},
"cursor": {
"hashes": [
"sha256:8ee9fe5b925e1001f6ae6c017e93682583d2b4d1ef7130a26cfcdf1651c0032c"
"sha256:7e728934f555a84a1c8b0850b66efcb580d092acc927b7d15dd43eb27dd4c4c5"
],
"version": "==1.2.0"
"version": "==1.3.1"
},
"distlib": {
"hashes": [
@@ -220,6 +183,13 @@
],
"version": "==0.14"
},
"entrypoints": {
"hashes": [
"sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19",
"sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"
],
"version": "==0.3"
},
"enum34": {
"hashes": [
"sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850",
@@ -227,7 +197,7 @@
"sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79",
"sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1"
],
"markers": "python_version < '3.4'",
"markers": "python_version < '3'",
"version": "==1.1.6"
},
"execnet": {
@@ -246,19 +216,18 @@
},
"flake8": {
"hashes": [
"sha256:7253265f7abd8b313e3892944044a365e3f4ac3fcdcfb4298f55ee9ddf188ba0",
"sha256:c7841163e2b576d435799169b78703ad6ac1bbb0f199994fc05f700b2a90ea37"
"sha256:c3ba1e130c813191db95c431a18cb4d20a468e98af7a77e2181b68574481ad36",
"sha256:fd9ddf503110bf3d8b1d270e8c673aab29ccb3dd6abf29bae1f54e5116ab4a91"
],
"index": "pypi",
"version": "==3.5.0"
"version": "==3.7.5"
},
"flaky": {
"hashes": [
"sha256:4ad7880aef8c35a34ddb394d4fa33047765bca1e3d67d182bf6eba9c8eabf3a2",
"sha256:d0533f473a46b916e6db6e84e20b06d8a70656600a0c14e819b0760b63f70226"
"sha256:12bd5e41f372b2190e8d754b6e5829c2f11dbc764e10b30f57e59f829c9ca1da",
"sha256:a94931c46a33469ec26f09b652bc88f55a8f5cc77807b90ca7bbafef1108fd7d"
],
"index": "pypi",
"version": "==3.4.0"
"version": "==3.5.3"
},
"flask": {
"hashes": [
@@ -272,29 +241,31 @@
"sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca",
"sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"
],
"markers": "python_version < '3.3'",
"markers": "python_version < '3.0'",
"version": "==1.0.2"
},
"future": {
"functools32": {
"hashes": [
"sha256:e39ced1ab767b5936646cedba8bcce582398233d6a627067d4c6a454c90cfedb"
"sha256:89d824aa6c358c421a234d7f9ee0bd75933a67c29588ce50aaa3acdf4d403fa0",
"sha256:f6253dfbe0538ad2e387bd8fdfd9293c925d63553f5813c4e587745416501e6d"
],
"version": "==0.16.0"
"markers": "python_version >= '2.7' and python_version < '2.8'",
"version": "==3.2.3.post2"
},
"futures": {
"hashes": [
"sha256:9ec02aa7d674acb8618afb127e27fde7fc68994c0437ad759fa094a574adb265",
"sha256:ec0a6cb848cc212002b9828c3e34c675e0c9ff6741dc445cab6fdd4e1085d1f1"
],
"markers": "python_version < '3' and python_version >= '2.6'",
"markers": "python_version < '3.0'",
"version": "==3.2.0"
},
"idna": {
"hashes": [
"sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
"sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
],
"version": "==2.7"
"version": "==2.8"
},
"imagesize": {
"hashes": [
@@ -337,11 +308,11 @@
},
"jedi": {
"hashes": [
"sha256:0191c447165f798e6a730285f2eee783fff81b0d3df261945ecb80983b5c3ca7",
"sha256:b7493f73a2febe0dc33d51c99b474547f7f6c0b2c8fb2b21f453eef204c12148"
"sha256:571702b5bd167911fe9036e5039ba67f820d6502832285cde8c881ab2b2149fd",
"sha256:c8481b5e59d34a5c7c42e98f6625e633f6ef59353abea6437472c7ec2093f191"
],
"index": "pypi",
"version": "==0.13.1"
"version": "==0.13.2"
},
"jinja2": {
"hashes": [
@@ -395,57 +366,66 @@
"sha256:5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1",
"sha256:b158b6df76edd239b8208d481dc46b6afd45a846b7812ff0ce58971cf5bc8bba"
],
"index": "pypi",
"version": "==2.0.0"
},
"more-itertools": {
"hashes": [
"sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092",
"sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e",
"sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d"
"sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4",
"sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc",
"sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9"
],
"version": "==4.3.0"
"markers": "python_version <= '2.7'",
"version": "==5.0.0"
},
"packaging": {
"hashes": [
"sha256:0886227f54515e592aaa2e5a553332c73962917f2831f1b0f9b9f4380a4b9807",
"sha256:f95a1e147590f204328170981833854229bb2912ac3d5f89e2a8ccd2834800c9"
"sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af",
"sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3"
],
"version": "==18.0"
"version": "==19.0"
},
"parso": {
"hashes": [
"sha256:35704a43a3c113cce4de228ddb39aab374b8004f4f2407d070b6a2ca784ce8a2",
"sha256:895c63e93b94ac1e1690f5fdd40b65f07c8171e3e53cbd7793b5b96c0e0a7f24"
"sha256:4580328ae3f548b358f4901e38c0578229186835f0fa0846e47369796dd5bcc9",
"sha256:68406ebd7eafe17f8e40e15a84b56848eccbf27d7c1feb89e93d8fca395706db"
],
"version": "==0.3.1"
"version": "==0.3.4"
},
"parver": {
"hashes": [
"sha256:ac4afff688d19d5e1876bb68d4bccc1a1b6a5cc8bd6a646939a14d366695ba15",
"sha256:f025fba8f88a9c776971df6d62b6cf7f37d1108f84c163bda91e157d7d527075"
"sha256:1b37a691af145a3a193eff269d53ba5b2ab16dfbb65d47d85360755919f5fe4b",
"sha256:72d056b8f8883ac90eef5554a9c8a47fac39d3b66479f3d2c8d5bc21b849cdba"
],
"index": "pypi",
"version": "==0.1.1"
"version": "==0.2.1"
},
"passa": {
"editable": true,
"git": "https://github.com/sarugaku/passa.git",
"ref": "4f3b8102f122cf0b75e5d7c513a2e61b0b093dcd"
"ref": "a2ba0b30c86339cae5ef3a03046fc9c583452c40",
"version": "==0.3.1.dev0"
},
"pathlib2": {
"hashes": [
"sha256:25199318e8cc3c25dcb45cbe084cc061051336d5a9ea2a12448d3d8cb748f742",
"sha256:5887121d7f7df3603bca2f710e7219f3eca0eb69e0b7cc6e0a022e155ac931a7"
],
"markers": "python_version < '3.5'",
"version": "==2.3.3"
},
"pbr": {
"hashes": [
"sha256:f59d71442f9ece3dffc17bc36575768e1ee9967756e6b6535f0ee1f0054c3d68",
"sha256:f6d5b23f226a2ba58e14e49aa3b1bfaf814d0199144b95d78458212444de1387"
"sha256:a7953f66e1f82e4b061f43096a4bcc058f7d3d41de9b94ac871770e8bdd831a2",
"sha256:d717573351cfe09f49df61906cd272abaa759b3e91744396b804965ff7bff38b"
],
"version": "==5.1.1"
"version": "==5.1.2"
},
"pep517": {
"hashes": [
"sha256:cc663a438fdfe2e88d8d3c5ef2203ac858de34e31b6609b1fc505d611490a926",
"sha256:f79bb08fb064dfc5b141204bfeb56a4141a6d504677fab4723036a464fc25cc1"
"sha256:43a7aa3902efd305a605c1028e4045968cd012831233ecab633a31d3ba4860a5",
"sha256:cb5ca55450b64e80744cd5c32f7d5b8928004042dfea50fdc3f96ad7f27cba96"
],
"version": "==0.3"
"version": "==0.5.0"
},
"pip-shims": {
"hashes": [
@@ -456,14 +436,15 @@
},
"pipenv": {
"editable": true,
"path": "."
"path": ".",
"version": "==2018.11.27.dev0"
},
"pkginfo": {
"hashes": [
"sha256:5878d542a4b3f237e359926384f1dde4e099c9f5525d236b1840cf704fa8d474",
"sha256:a39076cb3eb34c333a0dd390b568e9e1e881c7bf2cc0aee12120636816f55aee"
"sha256:7424f2c8511c186cd5424bbf31045b77435b37a8d604990b79d4e70d741148bb",
"sha256:a6d9e40ca61ad3ebd0b72fbadd4fba16e4c0e4df0428c041e01e06eb6ee71f32"
],
"version": "==1.4.2"
"version": "==1.5.0.1"
},
"plette": {
"extras": [
@@ -477,10 +458,10 @@
},
"pluggy": {
"hashes": [
"sha256:447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095",
"sha256:bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f"
"sha256:8ddc32f03971bfdf900a81961a48ccf2fb677cf7715108f85295c67405798616",
"sha256:980710797ff6a041e9a73a5787804f848996ecaa6f8a1b1e08224a5894f2074a"
],
"version": "==0.8.0"
"version": "==0.8.1"
},
"py": {
"hashes": [
@@ -491,72 +472,64 @@
},
"pycodestyle": {
"hashes": [
"sha256:cbc619d09254895b0d12c2c691e237b2e91e9b2ecf5e84c26b35400f93dcfb83",
"sha256:cbfca99bd594a10f674d0cd97a3d802a1fdef635d4361e1a2658de47ed261e3a"
"sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56",
"sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"
],
"version": "==2.4.0"
},
"pycparser": {
"hashes": [
"sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"
],
"version": "==2.19"
"version": "==2.5.0"
},
"pyflakes": {
"hashes": [
"sha256:9a7662ec724d0120012f6e29d6248ae3727d821bba522a0e6b356eff19126a49",
"sha256:f661252913bc1dbe7fcfcbf0af0db3f42ab65aabd1a6ca68fe5d466bace94dae"
"sha256:5e8c00e30c464c99e0b501dc160b13a14af7f27d4dffb529c556e30a159e231d",
"sha256:f277f9ca3e55de669fba45b7393a1449009cff5a37d1af10ebb76c52765269cd"
],
"version": "==2.0.0"
"version": "==2.1.0"
},
"pygments": {
"hashes": [
"sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d",
"sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc"
"sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a",
"sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d"
],
"version": "==2.2.0"
"version": "==2.3.1"
},
"pyparsing": {
"hashes": [
"sha256:40856e74d4987de5d01761a22d1621ae1c7f8774585acae358aa5c5936c6c90b",
"sha256:f353aab21fd474459d97b709e527b5571314ee5f067441dc9f88e33eecd96592"
"sha256:66c9268862641abcac4a96ba74506e594c884e3f57690a696d21ad8210ed667a",
"sha256:f6c5ef0d7480ad048c054c37632c67fca55299990fff127850181659eea33fc3"
],
"version": "==2.3.0"
"version": "==2.3.1"
},
"pytest": {
"hashes": [
"sha256:7e258ee50338f4e46957f9e09a0f10fb1c2d05493fa901d113a8dafd0790de4e",
"sha256:9332147e9af2dcf46cd7ceb14d5acadb6564744ddff1fe8c17f0ce60ece7d9a2"
"sha256:3f193df1cfe1d1609d4c583838bea3d532b18d6160fd3f55c9447fdca30848ec",
"sha256:e246cf173c01169b9617fc07264b7b1316e78d7a650055235d6d897bc80d9660"
],
"index": "pypi",
"version": "==3.8.2"
"version": "==3.10.1"
},
"pytest-forked": {
"hashes": [
"sha256:e4500cd0509ec4a26535f7d4112a8cc0f17d3a41c29ffd4eab479d2a55b30805",
"sha256:f275cb48a73fc61a6710726348e1da6d68a978f0ec0c54ece5a5fae5977e5a08"
"sha256:5fe33fbd07d7b1302c95310803a5e5726a4ff7f19d5a542b7ce57c76fed8135f",
"sha256:d352aaced2ebd54d42a65825722cb433004b4446ab5d2044851d9cc7a00c9e38"
],
"version": "==0.2"
"version": "==1.0.2"
},
"pytest-pypy": {
"pytest-pypi": {
"editable": true,
"path": "./tests/pytest-pypi"
"path": "./tests/pytest-pypi",
"version": "==0.1.1"
},
"pytest-tap": {
"hashes": [
"sha256:3b05ec931424bbe44e944726b68f7ef185bb6d25ce9ce21ac52c9af7ffa9b506",
"sha256:ca063de56298034302f3cbce55c87a27d7bfa7af7de591cdb9ec6ce45fea5467"
],
"index": "pypi",
"version": "==2.3"
},
"pytest-xdist": {
"hashes": [
"sha256:06aa39361694c9365baaa03bec71159b59ad06c9826c6279ebba368cb3571561",
"sha256:1ef0d05c905cfa0c5442c90e9e350e65c6ada120e33a00a066ca51c89f5f869a"
"sha256:4a201bb3ee60f5dd6bb40c5209d4e491cecc4d5bafd656cfb10f86178786e568",
"sha256:d03d1ff1b008458ed04fa73e642d840ac69b4107c168e06b71037c62d7813dd4"
],
"index": "pypi",
"version": "==1.23.2"
"version": "==1.26.1"
},
"pytoml": {
"hashes": [
@@ -566,11 +539,11 @@
},
"pytz": {
"hashes": [
"sha256:a061aa0a9e06881eb8b3b2b43f05b9439d6583c206d0a6c340ff72a7b6669053",
"sha256:ffb9ef1de172603304d9d2819af6f5ece76f2e85ec10692a524dd876e72bf277"
"sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9",
"sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c"
],
"index": "pypi",
"version": "==2018.5"
"version": "==2018.9"
},
"readme-renderer": {
"hashes": [
@@ -581,24 +554,24 @@
},
"requests": {
"hashes": [
"sha256:65b3a120e4329e33c9889db89c80976c5272f56ea92d3e74da8a463992e3ff54",
"sha256:ea881206e59f41dbd0bd445437d792e43906703fff75ca8ff43ccdb11f33f263"
"sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e",
"sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"
],
"version": "==2.20.1"
"version": "==2.21.0"
},
"requests-toolbelt": {
"hashes": [
"sha256:42c9c170abc2cacb78b8ab23ac957945c7716249206f90874651971a4acff237",
"sha256:f6a531936c6fa4c6cfce1b9c10d5c4f498d16528d2a54a22ca00011205a187b5"
"sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f",
"sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"
],
"version": "==0.8.0"
"version": "==0.9.1"
},
"requirementslib": {
"hashes": [
"sha256:441a5bfa487d3f3f5fd5d81c27071d9fd36bb385f538b3a87d20556a80b76f76",
"sha256:89e1e02ff0b52ce9c610124eb990ae706e0aee08beef8c718e7b87e470cdceeb"
"sha256:c26feee79853dedddab550cf79fb2fa83b4bc1a16eab58f2c870e8314caa6cc5",
"sha256:d302b780afbd1d60f49d368b535929d8ff4b6d972797f3777c9560d48abdded7"
],
"version": "==1.3.1.post1"
"version": "==1.4.0"
},
"resolvelib": {
"hashes": [
@@ -609,17 +582,34 @@
},
"rope": {
"hashes": [
"sha256:a108c445e1cd897fe19272ab7877d172e7faf3d4148c80e7d20faba42ea8f7b2"
"sha256:031eb54b3eeec89f4304ede816995ed2b93a21e6fba16bd02aff10a0d6c257b7"
],
"index": "pypi",
"version": "==0.11.0"
"version": "==0.12.0"
},
"scandir": {
"hashes": [
"sha256:04b8adb105f2ed313a7c2ef0f1cf7aff4871aa7a1883fa4d8c44b5551ab052d6",
"sha256:1444134990356c81d12f30e4b311379acfbbcd03e0bab591de2696a3b126d58e",
"sha256:1b5c314e39f596875e5a95dd81af03730b338c277c54a454226978d5ba95dbb6",
"sha256:346619f72eb0ddc4cf355ceffd225fa52506c92a2ff05318cfabd02a144e7c4e",
"sha256:44975e209c4827fc18a3486f257154d34ec6eaec0f90fef0cca1caa482db7064",
"sha256:61859fd7e40b8c71e609c202db5b0c1dbec0d5c7f1449dec2245575bdc866792",
"sha256:a5e232a0bf188362fa00123cc0bb842d363a292de7126126df5527b6a369586a",
"sha256:c14701409f311e7a9b7ec8e337f0815baf7ac95776cc78b419a1e6d49889a383",
"sha256:c7708f29d843fc2764310732e41f0ce27feadde453261859ec0fca7865dfc41b",
"sha256:c9009c527929f6e25604aec39b0a43c3f831d2947d89d6caaab22f057b7055c8",
"sha256:f5c71e29b4e2af7ccdc03a020c626ede51da471173b4a6ad1e904f2b2e04b4bd"
],
"markers": "python_version < '3.5'",
"version": "==1.9.0"
},
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
],
"version": "==1.11.0"
"version": "==1.12.0"
},
"snowballstemmer": {
"hashes": [
@@ -628,6 +618,13 @@
],
"version": "==1.2.1"
},
"soupsieve": {
"hashes": [
"sha256:afa56bf14907bb09403e5d15fbed6275caa4174d36b975226e3b67a3bb6e2c4b",
"sha256:eaed742b48b1f3e2d45ba6f79401b2ed5dc33b2123dfe216adb90d4bfa0ade26"
],
"version": "==1.8"
},
"sphinx": {
"hashes": [
"sha256:11f271e7a9398385ed730e90f0bb41dc3815294bdcd395b46ed2d033bc2e7d87",
@@ -638,18 +635,11 @@
},
"sphinx-click": {
"hashes": [
"sha256:0550d3e5dcd6244847bd0861ebe64101a2ef302913866e0ccd9095b2aa230051",
"sha256:404784f724504e3da2cb056767ba64955c4bfb9bfca8cfedd7142a962bafd70f"
"sha256:926da1a7c677ae1b35cf255269ff84fec65d0f92e4863acfa77b92cf8ae32275",
"sha256:f0c03d6ea0e4258c9c09646b6f745090ea8dd13e7e045903e4b789dfc02f7846"
],
"index": "pypi",
"version": "==1.3.0"
},
"sphinxcontrib-websupport": {
"hashes": [
"sha256:68ca7ff70785cbe1e7bccc71a48b5b6d965d79ca50629606c7861a21b206d9dd",
"sha256:9de47f375baf1ea07cdb3436ff39d7a9c76042c10a769c52353ec46e4e8fc3b9"
],
"version": "==1.1.0"
"version": "==2.0.1"
},
"stdeb": {
"hashes": [
@@ -669,45 +659,47 @@
"toml": {
"hashes": [
"sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c",
"sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"
"sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e",
"sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"
],
"version": "==0.10.0"
},
"tomlkit": {
"hashes": [
"sha256:82a8fbb8d8c6af72e96ba00b9db3e20ef61be6c79082552c9363f4559702258b",
"sha256:a43e0195edc9b3c198cd4b5f0f3d427a395d47c4a76ceba7cc875ed030756c39"
"sha256:d6506342615d051bc961f70bfcfa3d29b6616cc08a3ddfd4bc24196f16fd4ec2",
"sha256:f077456d35303e7908cc233b340f71e0bec96f63429997f38ca9272b7d64029e"
],
"version": "==0.5.2"
"version": "==0.5.3"
},
"towncrier": {
"editable": true,
"git": "https://github.com/hawkowl/towncrier.git",
"ref": "47754a607a9b03f06affaf167d65b990786aae25"
"ref": "ecd438c9c0ef132a92aba2eecc4dc672ccf9ec63",
"version": "==19.2.0"
},
"tqdm": {
"hashes": [
"sha256:3c4d4a5a41ef162dd61f1edb86b0e1c7859054ab656b2e7c7b77e7fbf6d9f392",
"sha256:5b4d5549984503050883bc126280b386f5f4ca87e6c023c5d015655ad75bdebb"
"sha256:d385c95361699e5cf7622485d9b9eae2d4864b21cd5a2374a9c381ffed701021",
"sha256:e22977e3ebe961f72362f6ddfb9197cc531c9737aaf5f607ef09740c849ecd05"
],
"version": "==4.28.1"
"version": "==4.31.1"
},
"twine": {
"hashes": [
"sha256:7d89bc6acafb31d124e6e5b295ef26ac77030bf098960c2a4c4e058335827c5c",
"sha256:fad6f1251195f7ddd1460cb76d6ea106c93adb4e56c41e0da79658e56e547d2c"
"sha256:0fb0bfa3df4f62076cab5def36b1a71a2e4acb4d1fa5c97475b048117b1a6446",
"sha256:d6c29c933ecfc74e9b1d9fa13aa1f87c5d5770e119f5a4ce032092f0ff5b14dc"
],
"index": "pypi",
"version": "==1.12.1"
"version": "==1.13.0"
},
"typing": {
"hashes": [
"sha256:3a887b021a77b292e151afb75323dea88a7bc1b3dfa92176cff8e44c8b68bddf",
"sha256:b2c689d54e1144bbcfd191b0832980a21c2dbcf7b5ff7a66248a60c90e951eb8",
"sha256:d400a9344254803a2368533e4533a4200d21eb7b6b729c173bc38201a74db3f2"
"sha256:4027c5f6127a6267a435201981ba156de91ad0d1d98e9ddc2aa173453453492d",
"sha256:57dcf675a99b74d64dacf6fba08fb17cf7e3d5fdff53d4a30ea2a5e7e52543d4",
"sha256:a4c8473ce11a65999c8f59cb093e70686b6c84c98df58c1dae9b3b196089858a"
],
"markers": "python_version < '3.5'",
"version": "==3.6.4"
"version": "==3.6.6"
},
"urllib3": {
"hashes": [
@@ -718,30 +710,33 @@
},
"virtualenv": {
"hashes": [
"sha256:686176c23a538ecc56d27ed9d5217abd34644823d6391cbeb232f42bf722baad",
"sha256:f899fafcd92e1150f40c8215328be38ff24b519cd95357fa6e78e006c7638208"
"sha256:8b9abfc51c38b70f61634bf265e5beacf6fae11fc25d355d1871f49b8e45f0db",
"sha256:cceab52aa7d4df1e1871a70236eb2b89fcfe29b6b43510d9738689787c513261"
],
"version": "==16.1.0"
"version": "==16.4.0"
},
"virtualenv-clone": {
"hashes": [
"sha256:afce268508aa5596c90dda234abe345deebc401a57d287bcbd76baa140a1aa58"
"sha256:217bd3f0880c9f85672c0bcc9ad9e0354ab7dfa89c2f117e63aa878b4279f5bf",
"sha256:316c8a05432a7adb5e461709759aca18c51433ffc2c33e2e80c9e51c452d339f",
"sha256:f2a07ed255f3abaceef8c8442512d8cdb2ba9f867e212d8a51680c7790a85033"
],
"version": "==0.4.0"
"version": "==0.5.1"
},
"vistir": {
"extras": [
"spinner"
],
"hashes": [
"sha256:851bd783f2b85a372e563db741dc689cb9263ce2e067e387facdca0c36b6a6ea",
"sha256:b38ffc8ef83f85d81b4efa4cd31ea3bcd37bdb2bc9e8da9f20a40859bc44b57e"
"sha256:510408ec63a4b423967fd630bf0885c8d6a1d5d126f8bb1be6aba86a0da5e815",
"sha256:fc5cca7a14e92feaa6f85dd91da74d834904280a96a21190aecb4cd1d1048e0e"
],
"version": "==0.2.4"
"version": "==0.3.0"
},
"webencodings": {
"hashes": [
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
"sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
],
"version": "==0.5.1"
},
@@ -754,17 +749,17 @@
},
"wheel": {
"hashes": [
"sha256:196c9842d79262bb66fcf59faa4bd0deb27da911dbc7c6cdca931080eb1f0783",
"sha256:c93e2d711f5f9841e17f53b0e6c0ff85593f3b416b6eec7a9452041a59a42688"
"sha256:12363e6df5678ecf9daf8429f06f97e7106e701405898f24318ce7f0b79c611a",
"sha256:b79ffea026bc0dbd940868347ae9eee36789b6496b6623bd2dec7c7c540a8f99"
],
"version": "==0.32.2"
"version": "==0.33.0"
},
"yaspin": {
"hashes": [
"sha256:36fdccc5e0637b5baa8892fe2c3d927782df7d504e9020f40eb2c1502518aa5a",
"sha256:8e52bf8079a48e2a53f3dfeec9e04addb900c101d1591c85df69cf677d3237e7"
"sha256:441f8a6761e347652d04614899fd0a9cfda7439e2d5682e664bd31230c656176",
"sha256:d3ebcf8162e0ef8bb5484b8751d5b6d2fbf0720112c81f64614c308576a03b1d"
],
"version": "==0.14.0"
"version": "==0.14.1"
}
}
}
+5 -5
View File
@@ -4,8 +4,8 @@ Pipenv: Python Development Workflow for Humans
[![image](https://img.shields.io/pypi/v/pipenv.svg)](https://python.org/pypi/pipenv)
[![image](https://img.shields.io/pypi/l/pipenv.svg)](https://python.org/pypi/pipenv)
[![image](https://badge.buildkite.com/79c7eccf056b17c3151f3c4d0e4c4b8b724539d84f1e037b9b.svg?branch=master)](https://code.kennethreitz.org/source/pipenv/)
[![VSTS build status (Windows)](https://dev.azure.com/pypa/pipenv/_apis/build/status/pipenv%20CI%20(Windows)?branchName=master&label=Windows)](https://dev.azure.com/pypa/pipenv/_build/latest?definitionId=9&branchName=master)
[![VSTS build status (Linux)](https://dev.azure.com/pypa/pipenv/_apis/build/status/pipenv%20CI%20(Linux)?branchName=master&label=Linux)](https://dev.azure.com/pypa/pipenv/_build/latest?definitionId=10&branchName=master)
[![Azure Pipelines build status (Linux)](https://dev.azure.com/pypa/pipenv/_apis/build/status/pipenv%20CI%20(Linux)?branchName=master&label=Linux)](https://dev.azure.com/pypa/pipenv/_build/latest?definitionId=13&branchName=master)
[![Azure Pipelines build status (Windows)](https://dev.azure.com/pypa/pipenv/_apis/build/status/pipenv%20CI%20(Windows)?branchName=master&label=Windows)](https://dev.azure.com/pypa/pipenv/_build/latest?definitionId=12&branchName=master)
[![image](https://img.shields.io/pypi/pyversions/pipenv.svg)](https://python.org/pypi/pipenv)
[![image](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/kennethreitz)
@@ -13,14 +13,14 @@ Pipenv: Python Development Workflow for Humans
**Pipenv** is a tool that aims to bring the best of all packaging worlds
(bundler, composer, npm, cargo, yarn, etc.) to the Python world.
*Windows is a first--class citizen, in our world.*
*Windows is a first-class citizen, in our world.*
It automatically creates and manages a virtualenv for your projects, as
well as adds/removes packages from your `Pipfile` as you
install/uninstall packages. It also generates the ever--important
install/uninstall packages. It also generates the ever-important
`Pipfile.lock`, which is used to produce deterministic builds.
![image](http://media.kennethreitz.com.s3.amazonaws.com/pipenv.gif)
![image](https://s3.amazonaws.com/media.kennethreitz.com/pipenv.gif)
The problems that Pipenv seeks to solve are multi-faceted:
+2 -2
View File
@@ -203,11 +203,11 @@ To make inclusive or exclusive version comparisons you can use: ::
$ pipenv install "requests<=2.13" # will install a version equal or lower than 2.13.0
$ pipenv install "requests>2.19" # will install 2.19.1 but not 2.19.0
.. note:: The use of ``" "`` around the package and version specification is highly recommended
.. note:: The use of double quotes around the package and version specification (i.e. ``"requests>2.19"``) is highly recommended
to avoid issues with `Input and output redirection <https://robots.thoughtbot.com/input-output-redirection-in-the-shell>`_
in Unix-based operating systems.
The use of ``~=`` is preferred over the ``==`` identifier as the former prevents pipenv from updating the packages: ::
The use of ``~=`` is preferred over the ``==`` identifier as the latter prevents pipenv from updating the packages: ::
$ pipenv install "requests~=2.2" # locks the major version of the package (this is equivalent to using ==2.*)
+1
View File
@@ -18,6 +18,7 @@
#
import os
# Path hackery to get current version number.
here = os.path.abspath(os.path.dirname(__file__))
+7 -8
View File
@@ -26,10 +26,12 @@ It automatically creates and manages a virtualenv for your projects, as well as
Pipenv is primarily meant to provide users and developers of applications with an easy method to setup a working environment. For the distinction between libraries and applications and the usage of ``setup.py`` vs ``Pipfile`` to define dependencies, see :ref:`pipfile-vs-setuppy`.
.. raw:: html
<iframe src="https://player.vimeo.com/video/233134524" width="700" height="460" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
.. image:: https://s3.amazonaws.com/media.kennethreitz.com/pipenv.gif
:height: 341px
:width: 654px
:scale: 100 %
:alt: a short animation of pipenv at work
The problems that Pipenv seeks to solve are multi-faceted:
- You no longer need to use ``pip`` and ``virtualenv`` separately. They work together.
@@ -49,7 +51,7 @@ You can quickly play with Pipenv right in your browser:
Install Pipenv Today!
---------------------
If you're on MacOS, you can install Pipenv easily with Homebrew::
If you're on MacOS, you can install Pipenv easily with Homebrew. You can also use Linuxbrew on Linux using the same command::
$ brew install pipenv
@@ -70,9 +72,6 @@ Otherwise, refer to the :ref:`installing-pipenv` chapter for instructions.
User Testimonials
-----------------
**Jannis Leidel**, former pip maintainer—
*Pipenv is the porcelain I always wanted to build for pip. It fits my brain and mostly replaces virtualenvwrapper and manual pip calls for me. Use it.*
**David Gang**
*This package manager is really awesome. For the first time I know exactly what my dependencies are which I installed and what the transitive dependencies are. Combined with the fact that installs are deterministic, makes this package manager first class, like cargo*.
+7 -7
View File
@@ -52,16 +52,16 @@ check this by running::
$ pip --version
pip 9.0.1
If you installed Python from source, with an installer from `python.org`_, or
via `Homebrew`_ you should already have pip. If you're on Linux and installed
If you installed Python from source, with an installer from `python.org`_, via `Homebrew`_ or via `Linuxbrew`_ you should already have pip. If you're on Linux and installed
using your OS package manager, you may have to `install pip <https://pip.pypa.io/en/stable/installing/>`_ separately.
If you plan to install Pipenv using Homebrew you can skip this step. The
Homebrew installer takes care of pip for you.
If you plan to install Pipenv using Homebrew or Linuxbrew you can skip this step. The
Homebrew/Linuxbrew installer takes care of pip for you.
.. _getting started tutorial: https://opentechschool.github.io/python-beginners/en/getting_started.html#what-is-python-exactly
.. _python.org: https://python.org
.. _Homebrew: https://brew.sh
.. _Linuxbrew: https://linuxbrew.sh/
.. _Installing Python: http://docs.python-guide.org/en/latest/starting/installation/
@@ -83,13 +83,13 @@ cases.
☤ Homebrew Installation of Pipenv
---------------------------------
Homebrew is a popular open-source package management system for macOS.
`Homebrew`_ is a popular open-source package management system for macOS. For Linux users, `Linuxbrew`_ is a Linux port of that.
Installing pipenv via Homebrew will keep pipenv and all of its dependencies in
Installing pipenv via Homebrew or Linuxbrew will keep pipenv and all of its dependencies in
an isolated virtual environment so it doesn't interfere with the rest of your
Python installation.
Once you have installed `Homebrew`_ simply run::
Once you have installed Homebrew or Linuxbrew simply run::
$ brew install pipenv
+16 -18
View File
@@ -1,28 +1,26 @@
alabaster==0.7.10
Babel==2.5.0
certifi==2017.7.27.1
Babel==2.6.0
certifi==2018.10.15
chardet==3.0.4
click==6.7
click==7.0
docutils==0.14
first==2.0.1
idna==2.6
imagesize==0.7.1
idna==2.7
imagesize==1.1.0
Jinja2==2.10
MarkupSafe==1.0
pbr==3.1.1
pip-tools==1.9.0
MarkupSafe==1.1.0
pbr==5.1.1
-e .
Pygments==2.2.0
Pygments==2.3.0
pythonz-bd==1.11.4
pytz==2017.2
requests==2.20.0
pytz==2018.5
requests==2.20.1
resumable-urlretrieve==0.1.5
semver==2.7.8
six==1.10.0
six==1.11.0
snowballstemmer==1.2.1
Sphinx==1.6.3
sphinx-click==1.2.0
sphinxcontrib-websupport==1.0.1
urllib3==1.22
virtualenv==15.1.0
virtualenv-clone==0.2.6
sphinx-click==1.3.0
sphinxcontrib-websupport==1.1.0
urllib3==1.24.1
virtualenv==16.1.0
virtualenv-clone==0.4.0
+1
View File
@@ -0,0 +1 @@
Raise `PipenvUsageError` when [[source]] does not contain url field.
+1
View File
@@ -0,0 +1 @@
Fixed a bug which caused editable package resolution to sometimes fail with an unhelpful setuptools-related error message.
+1
View File
@@ -0,0 +1 @@
Dependency resolution now writes hashes for local and remote files to the lockfile.
+1
View File
@@ -0,0 +1 @@
Fixed a bug which prevented ``pipenv graph`` from correctly showing all dependencies when running from within ``pipenv shell``.
+1
View File
@@ -0,0 +1 @@
Fixed resolution of direct-url dependencies in ``setup.py`` files to respect ``PEP-508`` style URL dependencies.
+1
View File
@@ -0,0 +1 @@
Added support for resolution of direct-url dependencies in ``setup.py`` files to respect ``PEP-508`` style URL dependencies.
-1
View File
@@ -1 +0,0 @@
Environment variables are expanded correctly before running scripts on POSIX.
-1
View File
@@ -1 +0,0 @@
Pipenv will no longer disable user-mode installation when the ``--system`` flag is passed in.
-1
View File
@@ -1 +0,0 @@
Fixed an issue with attempting to render unicode output in non-unicode locales.
-1
View File
@@ -1 +0,0 @@
Fixed a bug which could cause failures to occur when parsing python entries from global pyenv version files.
-1
View File
@@ -1 +0,0 @@
Fixed an issue which prevented the parsing of named extras sections from certain ``setup.py`` files.
-1
View File
@@ -1 +0,0 @@
Correctly detect the virtualenv location inside an activated virtualenv.
-1
View File
@@ -1 +0,0 @@
Fixed a bug which caused spinner frames to be written to stdout during locking operations which could cause redirection pipes to fail.
-1
View File
@@ -1 +0,0 @@
Fixed a bug that editable pacakges can't be uninstalled correctly.
-1
View File
@@ -1 +0,0 @@
Adding normal pep 508 compatible markers is now fully functional when using VCS dependencies.
-1
View File
@@ -1 +0,0 @@
Updated ``requirementslib`` and ``pythonfinder`` for multiple bugfixes.
-1
View File
@@ -1 +0,0 @@
Fixed an issue where pipenv could crash when multiple pipenv processes attempted to create the same directory.
+1
View File
@@ -0,0 +1 @@
Update pytest-pypi documentation not to be pytest-httpbin documentation.
+3
View File
@@ -0,0 +1,3 @@
Fixed a bug which caused failures in warning reporting when running pipenv inside a virtualenv under some circumstances.
- Fixed a bug with package discovery when running ``pipenv clean``.
+5
View File
@@ -0,0 +1,5 @@
Added full support for resolution of all dependency types including direct URLs, zip archives, tarballs, etc.
- Improved error handling and formatting.
- Introduced improved cross platform stream wrappers for better ``stdout`` and ``stderr`` consistency.
+28
View File
@@ -0,0 +1,28 @@
Updated vendored dependencies:
- **attrs**: ``18.2.0`` => ``19.1.0``
- **certifi**: ``2018.10.15`` => ``2018.11.29``
- **cached_property**: ``1.4.3`` => ``1.5.1``
- **colorama**: ``0.3.9`` => ``0.4.1``
- **idna**: ``2.7`` => ``2.8``
- **markupsafe**: ``1.0`` => ``1.1.1``
- **orderedmultidict**: ``(new)`` => ``1.0``
- **packaging**: ``18.0`` => ``19.0``
- **parse**: ``1.9.0`` => ``1.11.1``
- **pathlib2**: ``2.3.2`` => ``2.3.3``
- **pep517**: ``(new)`` => ``0.5.0``
- **pipdeptree**: ``0.13.0`` => ``0.13.2``
- **pyparsing**: ``2.2.2`` => ``2.3.1``
- **python-dotenv**: ``0.9.1`` => ``0.10.1``
- **pythonfinder**: ``1.1.10`` => ``1.2.0``
- **pytoml**: ``(new)`` => ``0.1.20``
- **requests**: ``2.20.1`` => ``2.21.0``
- **requirementslib**: ``1.3.3`` => ``1.4.2``
- **shellingham**: ``1.2.7`` => ``1.2.8``
- **six**: ``1.11.0`` => ``1.12.0``
- **tomlkit**: ``0.5.2`` => ``0.5.3``
- **urllib3**: ``1.24`` => ``1.24.1``
- **vistir**: ``0.3.0`` => ``0.3.1``
- **yaspin**: ``0.14.0`` => ``0.14.1``
- Removed vendored dependency **cursor**.
+1
View File
@@ -0,0 +1 @@
Quote command arguments with carets (``^``) on Windows to work around unintended shell escapes.
+1
View File
@@ -0,0 +1 @@
Handle alternate names for UTF-8 encoding.
+1
View File
@@ -0,0 +1 @@
Abort pipenv before adding the non-exist package to Pipfile.
+1
View File
@@ -0,0 +1 @@
Don't normalize the package name user passes in.
+1
View File
@@ -0,0 +1 @@
Pipenv will now successfully recursively lock VCS sub-dependencies.
+1
View File
@@ -0,0 +1 @@
Fix a bug where custom virtualenv can not be activated with pipenv shell
+1
View File
@@ -0,0 +1 @@
Added support for ``--verbose`` output to ``pipenv run``.
+1
View File
@@ -0,0 +1 @@
Fix a bug that ``--site-packages`` flag is not recognized.
+1
View File
@@ -0,0 +1 @@
The inline tables won't be rewritten now.
+1
View File
@@ -0,0 +1 @@
Pipenv will now discover and resolve the intrinsic dependencies of **all** VCS dependencies, whether they are editable or not, to prevent resolution conflicts.
+1
View File
@@ -0,0 +1 @@
Fix unhashable type error during ``$ pipenv install --selective-upgrade``
+1
View File
@@ -0,0 +1 @@
Fixed a keyerror which could occur when locking VCS dependencies in some cases.
+1
View File
@@ -0,0 +1 @@
Fixed a bug that ``ValidationError`` is thrown when some fields are missing in source section.
+1
View File
@@ -0,0 +1 @@
Fixed the wrong order of old and new hashes in message.
+1
View File
@@ -0,0 +1 @@
Updated the index names in lock file when source name in Pipfile is changed.
+1
View File
@@ -0,0 +1 @@
Replace (non-existant) video on docs index.rst with equivalent gif.
+1
View File
@@ -0,0 +1 @@
Fix bug causing ``[SSL: CERTIFICATE_VERIFY_FAILED]`` when Pipfile ``[[source]]`` has verify_ssl=false and url with custom port.
+1
View File
@@ -0,0 +1 @@
Clarify wording in Basic Usage example on using double quotes to escape shell redirection
+1
View File
@@ -0,0 +1 @@
Fix the issue that lock file can't be created when ``PIPENV_PIPFILE`` is not under working directory.
+1
View File
@@ -0,0 +1 @@
Added the ability for Windows users to enable emojis by setting ``PIPENV_HIDE_EMOJIS=0``.
+9
View File
@@ -0,0 +1,9 @@
## PEEP-003: Subcommands
NOT YET ACCEPTED
Pipenv will automatically run commands like "pipenv deploy" if the "pipenv-deploy" binary is available on the path.
These subcommands cannot overwrite built-in commands.
These subcommands will receive environment variables with contextual information.
+9
View File
@@ -0,0 +1,9 @@
# PEEP-003: Revocation of Power of BDFL
**ACCEPTED**
Pipenv will be governed by a board of maintainers (trusted collaborators to the project on GitHub), not a BDFL.
The BDFL retains his title, however, revokes himself of his powers.
PEEP approval will be determined by available members of the board of maintainers, in private or public channels.
+2
View File
@@ -10,6 +10,7 @@ import warnings
from .__version__ import __version__
PIPENV_ROOT = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
PIPENV_VENDOR = os.sep.join([PIPENV_ROOT, "vendor"])
PIPENV_PATCHED = os.sep.join([PIPENV_ROOT, "patched"])
@@ -20,6 +21,7 @@ sys.path.insert(0, PIPENV_PATCHED)
from pipenv.vendor.urllib3.exceptions import DependencyWarning
from pipenv.vendor.vistir.compat import ResourceWarning, fs_str
warnings.filterwarnings("ignore", category=DependencyWarning)
warnings.filterwarnings("ignore", category=ResourceWarning)
warnings.filterwarnings("ignore", category=UserWarning)
+2 -1
View File
@@ -1,4 +1,5 @@
from .cli import cli
if __name__ == "__main__":
cli(auto_envvar_prefix="PIPENV")
cli()
+1 -1
View File
@@ -2,4 +2,4 @@
# // ) ) / / // ) ) //___) ) // ) ) || / /
# //___/ / / / //___/ / // // / / || / /
# // / / // ((____ // / / ||/ /
__version__ = "2018.11.15.dev0"
__version__ = "2018.11.27.dev0"
+37 -285
View File
@@ -5,39 +5,17 @@ Exposes a standard API that enables compatibility across python versions,
operating systems, etc.
"""
import functools
import importlib
import io
import os
import six
import sys
import warnings
import six
import vistir
from tempfile import _bin_openflags, gettempdir, _mkstemp_inner, mkdtemp
try:
from tempfile import _infer_return_type
except ImportError:
from .vendor.vistir.compat import (
NamedTemporaryFile, Path, ResourceWarning, TemporaryDirectory
)
def _infer_return_type(*args):
_types = set()
for arg in args:
if isinstance(type(arg), six.string_types):
_types.add(str)
elif isinstance(type(arg), bytes):
_types.add(bytes)
elif arg:
_types.add(type(arg))
return _types.pop()
if sys.version_info[:2] >= (3, 5):
try:
from pathlib import Path
except ImportError:
from .vendor.pathlib2 import Path
else:
from .vendor.pathlib2 import Path
# Backport required for earlier versions of Python.
if sys.version_info < (3, 3):
@@ -45,257 +23,14 @@ if sys.version_info < (3, 3):
else:
from shutil import get_terminal_size
try:
from weakref import finalize
except ImportError:
try:
from .vendor.backports.weakref import finalize
except ImportError:
class finalize(object):
def __init__(self, *args, **kwargs):
from .utils import logging
logging.warn("weakref.finalize unavailable, not cleaning...")
def detach(self):
return False
from vistir.compat import ResourceWarning
warnings.filterwarnings("ignore", category=ResourceWarning)
class TemporaryDirectory(object):
"""
Create and return a temporary directory. This has the same
behavior as mkdtemp but can be used as a context manager. For
example:
with TemporaryDirectory() as tmpdir:
...
Upon exiting the context, the directory and everything contained
in it are removed.
"""
def __init__(self, suffix="", prefix="", dir=None):
if "RAM_DISK" in os.environ:
import uuid
name = uuid.uuid4().hex
dir_name = os.path.join(os.environ["RAM_DISK"].strip(), name)
os.mkdir(dir_name)
self.name = dir_name
else:
self.name = mkdtemp(suffix, prefix, dir)
self._finalizer = finalize(
self,
self._cleanup,
self.name,
warn_message="Implicitly cleaning up {!r}".format(self),
)
@classmethod
def _cleanup(cls, name, warn_message):
vistir.path.rmtree(name)
warnings.warn(warn_message, ResourceWarning)
def __repr__(self):
return "<{} {!r}>".format(self.__class__.__name__, self.name)
def __enter__(self):
return self
def __exit__(self, exc, value, tb):
self.cleanup()
def cleanup(self):
if self._finalizer.detach():
vistir.path.rmtree(self.name)
def _sanitize_params(prefix, suffix, dir):
"""Common parameter processing for most APIs in this module."""
output_type = _infer_return_type(prefix, suffix, dir)
if suffix is None:
suffix = output_type()
if prefix is None:
if output_type is str:
prefix = "tmp"
else:
prefix = os.fsencode("tmp")
if dir is None:
if output_type is str:
dir = gettempdir()
else:
dir = os.fsencode(gettempdir())
return prefix, suffix, dir, output_type
class _TemporaryFileCloser:
"""
A separate object allowing proper closing of a temporary file's
underlying file object, without adding a __del__ method to the
temporary file.
"""
file = None # Set here since __del__ checks it
close_called = False
def __init__(self, file, name, delete=True):
self.file = file
self.name = name
self.delete = delete
# NT provides delete-on-close as a primitive, so we don't need
# the wrapper to do anything special. We still use it so that
# file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile.
if os.name != "nt":
# Cache the unlinker so we don't get spurious errors at
# shutdown when the module-level "os" is None'd out. Note
# that this must be referenced as self.unlink, because the
# name TemporaryFileWrapper may also get None'd out before
# __del__ is called.
def close(self, unlink=os.unlink):
if not self.close_called and self.file is not None:
self.close_called = True
try:
self.file.close()
finally:
if self.delete:
unlink(self.name)
# Need to ensure the file is deleted on __del__
def __del__(self):
self.close()
else:
def close(self):
if not self.close_called:
self.close_called = True
self.file.close()
class _TemporaryFileWrapper:
"""
Temporary file wrapper
This class provides a wrapper around files opened for
temporary use. In particular, it seeks to automatically
remove the file when it is no longer needed.
"""
def __init__(self, file, name, delete=True):
self.file = file
self.name = name
self.delete = delete
self._closer = _TemporaryFileCloser(file, name, delete)
def __getattr__(self, name):
# Attribute lookups are delegated to the underlying file
# and cached for non-numeric results
# (i.e. methods are cached, closed and friends are not)
file = self.__dict__["file"]
a = getattr(file, name)
if hasattr(a, "__call__"):
func = a
@functools.wraps(func)
def func_wrapper(*args, **kwargs):
return func(*args, **kwargs)
# Avoid closing the file as long as the wrapper is alive,
# see issue #18879.
func_wrapper._closer = self._closer
a = func_wrapper
if not isinstance(a, int):
setattr(self, name, a)
return a
# The underlying __enter__ method returns the wrong object
# (self.file) so override it to return the wrapper
def __enter__(self):
self.file.__enter__()
return self
# Need to trap __exit__ as well to ensure the file gets
# deleted when used in a with statement
def __exit__(self, exc, value, tb):
result = self.file.__exit__(exc, value, tb)
self.close()
return result
def close(self):
"""
Close the temporary file, possibly deleting it.
"""
self._closer.close()
# iter() doesn't use __getattr__ to find the __iter__ method
def __iter__(self):
# Don't return iter(self.file), but yield from it to avoid closing
# file as long as it's being used as iterator (see issue #23700). We
# can't use 'yield from' here because iter(file) returns the file
# object itself, which has a close method, and thus the file would get
# closed when the generator is finalized, due to PEP380 semantics.
for line in self.file:
yield line
def NamedTemporaryFile(
mode="w+b",
buffering=-1,
encoding=None,
newline=None,
suffix=None,
prefix=None,
dir=None,
delete=True,
):
"""
Create and return a temporary file.
Arguments:
'prefix', 'suffix', 'dir' -- as for mkstemp.
'mode' -- the mode argument to io.open (default "w+b").
'buffering' -- the buffer size argument to io.open (default -1).
'encoding' -- the encoding argument to io.open (default None)
'newline' -- the newline argument to io.open (default None)
'delete' -- whether the file is deleted on close (default True).
The file is created as mkstemp() would do it.
Returns an object with a file-like interface; the name of the file
is accessible as its 'name' attribute. The file will be automatically
deleted when it is closed unless the 'delete' argument is set to False.
"""
prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
flags = _bin_openflags
# Setting O_TEMPORARY in the flags causes the OS to delete
# the file when it is closed. This is only supported by Windows.
if os.name == "nt" and delete:
flags |= os.O_TEMPORARY
if sys.version_info < (3, 5):
(fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
else:
(fd, name) = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
try:
file = io.open(
fd, mode, buffering=buffering, newline=newline, encoding=encoding
)
return _TemporaryFileWrapper(file, name, delete)
except BaseException:
os.unlink(name)
os.close(fd)
raise
__all__ = [
"NamedTemporaryFile", "Path", "ResourceWarning", "TemporaryDirectory",
"get_terminal_size", "getpreferredencoding", "DEFAULT_ENCODING", "canonical_encoding_name",
"force_encoding", "UNICODE_TO_ASCII_TRANSLATION_MAP", "decode_output", "fix_utf8"
]
def getpreferredencoding():
@@ -313,6 +48,16 @@ def getpreferredencoding():
DEFAULT_ENCODING = getpreferredencoding()
def canonical_encoding_name(name):
import codecs
try:
codec = codecs.lookup(name)
except LookupError:
return name
else:
return codec.name
# From https://github.com/CarlFK/veyepar/blob/5c5de47/dj/scripts/fixunicode.py
# MIT LIcensed, thanks Carl!
def force_encoding():
@@ -324,20 +69,23 @@ def force_encoding():
else:
if not (stdout_isatty() and stderr_isatty()):
return DEFAULT_ENCODING, DEFAULT_ENCODING
stdout_encoding = sys.stdout.encoding
stderr_encoding = sys.stderr.encoding
stdout_encoding = canonical_encoding_name(sys.stdout.encoding)
stderr_encoding = canonical_encoding_name(sys.stderr.encoding)
if sys.platform == "win32" and sys.version_info >= (3, 1):
return DEFAULT_ENCODING, DEFAULT_ENCODING
if stdout_encoding.lower() != "utf-8" or stderr_encoding.lower() != "utf-8":
if stdout_encoding != "utf-8" or stderr_encoding != "utf-8":
from ctypes import pythonapi, py_object, c_char_p
try:
from ctypes import pythonapi, py_object, c_char_p
except ImportError:
return DEFAULT_ENCODING, DEFAULT_ENCODING
try:
PyFile_SetEncoding = pythonapi.PyFile_SetEncoding
except AttributeError:
return DEFAULT_ENCODING, DEFAULT_ENCODING
else:
PyFile_SetEncoding.argtypes = (py_object, c_char_p)
if stdout_encoding.lower() != "utf-8":
if stdout_encoding != "utf-8":
try:
was_set = PyFile_SetEncoding(sys.stdout, "utf-8")
except OSError:
@@ -347,7 +95,7 @@ def force_encoding():
else:
stdout_encoding = "utf-8"
if stderr_encoding.lower() != "utf-8":
if stderr_encoding != "utf-8":
try:
was_set = PyFile_SetEncoding(sys.stderr, "utf-8")
except OSError:
@@ -366,11 +114,17 @@ OUT_ENCODING, ERR_ENCODING = force_encoding()
UNICODE_TO_ASCII_TRANSLATION_MAP = {
8230: u"...",
8211: u"-",
10004: u"x",
10008: u"Ok"
10004: u"OK",
10008: u"x",
}
def decode_for_output(output, target=sys.stdout):
return vistir.misc.decode_for_output(
output, sys.stdout, translation_map=UNICODE_TO_ASCII_TRANSLATION_MAP
)
def decode_output(output):
if not isinstance(output, six.string_types):
return output
@@ -384,13 +138,11 @@ def decode_output(output):
output = output.translate(UNICODE_TO_ASCII_TRANSLATION_MAP)
output = output.encode(DEFAULT_ENCODING, "replace")
return vistir.misc.to_text(output, encoding=DEFAULT_ENCODING, errors="replace")
return output
def fix_utf8(text):
if not isinstance(text, six.string_types):
return text
from ._compat import decode_output
try:
text = decode_output(text)
except UnicodeDecodeError:
+1
View File
@@ -1,3 +1,4 @@
# -*- coding=utf-8 -*-
from __future__ import absolute_import
from .command import cli
+46 -38
View File
@@ -4,39 +4,41 @@ from __future__ import absolute_import
import os
import sys
import crayons
import delegator
from click import (
argument, echo, edit, group, option, pass_context, secho, version_option
)
import click_completion
from click_didyoumean import DYMCommandCollection
import crayons
import delegator
from ..__version__ import __version__
from .options import (
CONTEXT_SETTINGS, PipenvGroup, code_option, common_options, deploy_option,
general_options, install_options, lock_options, pass_state, skip_lock_option,
pypi_mirror_option, python_option, requirementstxt_option, sync_options,
system_option, three_option, verbose_option, uninstall_options
general_options, install_options, lock_options, pass_state,
pypi_mirror_option, python_option, requirementstxt_option,
skip_lock_option, sync_options, system_option, three_option,
uninstall_options, verbose_option
)
# Enable shell completion.
click_completion.init()
subcommand_context = CONTEXT_SETTINGS.copy()
subcommand_context.update({
"ignore_unknown_options": True,
"allow_extra_args": True
})
subcommand_context_no_interspersion = subcommand_context.copy()
subcommand_context_no_interspersion["allow_interspersed_args"] = False
@group(cls=PipenvGroup, invoke_without_command=True, context_settings=CONTEXT_SETTINGS)
@option("--where", is_flag=True, default=False, help="Output project home information.")
@option("--venv", is_flag=True, default=False, help="Output virtualenv information.")
@option(
"--py", is_flag=True, default=False, help="Output Python interpreter information."
)
@option(
"--envs", is_flag=True, default=False, help="Output Environment Variable options."
)
@option("--py", is_flag=True, default=False, help="Output Python interpreter information.")
@option("--envs", is_flag=True, default=False, help="Output Environment Variable options.")
@option("--rm", is_flag=True, default=False, help="Remove the virtualenv.")
@option("--bare", is_flag=True, default=False, help="Minimal output.")
@option(
@@ -66,7 +68,6 @@ def cli(
python=False,
help=False,
py=False,
site_packages=False,
envs=False,
man=False,
completion=False,
@@ -194,7 +195,7 @@ def cli(
)
ctx.abort()
# --two / --three was passed…
if (state.python or state.three is not None) or site_packages:
if (state.python or state.three is not None) or state.site_packages:
ensure_project(
three=state.three,
python=state.python,
@@ -211,7 +212,7 @@ def cli(
@cli.command(
short_help="Installs provided packages and adds them to Pipfile, or (if no packages are given), installs all packages from Pipfile.",
context_settings=dict(ignore_unknown_options=True, allow_extra_args=True),
context_settings=subcommand_context,
)
@system_option
@code_option
@@ -253,8 +254,10 @@ def install(
ctx.abort()
@cli.command(short_help="Un-installs a provided package and removes it from Pipfile.")
@option("--skip-lock/--lock", is_flag=True, default=False, help="Lock afterwards.")
@cli.command(
short_help="Un-installs a provided package and removes it from Pipfile.",
context_settings=subcommand_context
)
@option(
"--all-dev",
is_flag=True,
@@ -273,7 +276,6 @@ def install(
def uninstall(
ctx,
state,
skip_lock=False,
all_dev=False,
all=False,
**kwargs
@@ -296,7 +298,8 @@ def uninstall(
if retcode:
sys.exit(retcode)
@cli.command(short_help="Generates Pipfile.lock.")
@cli.command(short_help="Generates Pipfile.lock.", context_settings=CONTEXT_SETTINGS)
@lock_options
@pass_state
@pass_context
@@ -328,7 +331,7 @@ def lock(
@cli.command(
short_help="Spawns a shell within the virtualenv.",
context_settings=dict(ignore_unknown_options=True, allow_extra_args=True),
context_settings=subcommand_context,
)
@option(
"--fancy",
@@ -387,11 +390,7 @@ def shell(
@cli.command(
add_help_option=False,
short_help="Spawns a command installed into the virtualenv.",
context_settings=dict(
ignore_unknown_options=True,
allow_interspersed_args=False,
allow_extra_args=True,
),
context_settings=subcommand_context_no_interspersion,
)
@common_options
@argument("command")
@@ -400,7 +399,6 @@ def shell(
def run(state, command, args):
"""Spawns a command installed into the virtualenv."""
from ..core import do_run
do_run(
command=command, args=args, three=state.three, python=state.python, pypi_mirror=state.pypi_mirror
)
@@ -408,7 +406,7 @@ def run(state, command, args):
@cli.command(
short_help="Checks for security vulnerabilities and against PEP 508 markers provided in Pipfile.",
context_settings=dict(ignore_unknown_options=True, allow_extra_args=True),
context_settings=subcommand_context
)
@option(
"--unused",
@@ -448,7 +446,7 @@ def check(
)
@cli.command(short_help="Runs lock, then sync.")
@cli.command(short_help="Runs lock, then sync.", context_settings=CONTEXT_SETTINGS)
@option("--bare", is_flag=True, default=False, help="Minimal output.")
@option(
"--outdated", is_flag=True, default=False, help=u"List out-of-date dependencies."
@@ -525,7 +523,10 @@ def update(
)
@cli.command(short_help=u"Displays currently-installed dependency graph information.")
@cli.command(
short_help=u"Displays currently-installed dependency graph information.",
context_settings=CONTEXT_SETTINGS
)
@option("--bare", is_flag=True, default=False, help="Minimal output.")
@option("--json", is_flag=True, default=False, help="Output JSON.")
@option("--json-tree", is_flag=True, default=False, help="Output JSON in nested tree.")
@@ -537,7 +538,10 @@ def graph(bare=False, json=False, json_tree=False, reverse=False):
do_graph(bare=bare, json=json, json_tree=json_tree, reverse=reverse)
@cli.command(short_help="View a given module in your editor.", name="open")
@cli.command(
short_help="View a given module in your editor.", name="open",
context_settings=CONTEXT_SETTINGS
)
@common_options
@argument("module", nargs=1)
@pass_state
@@ -576,7 +580,10 @@ def run_open(state, module, *args, **kwargs):
return 0
@cli.command(short_help="Installs all packages specified in Pipfile.lock.")
@cli.command(
short_help="Installs all packages specified in Pipfile.lock.",
context_settings=CONTEXT_SETTINGS
)
@option("--bare", is_flag=True, default=False, help="Minimal output.")
@sync_options
@pass_state
@@ -609,7 +616,10 @@ def sync(
ctx.abort()
@cli.command(short_help="Uninstalls all packages not specified in Pipfile.lock.")
@cli.command(
short_help="Uninstalls all packages not specified in Pipfile.lock.",
context_settings=CONTEXT_SETTINGS
)
@option("--bare", is_flag=True, default=False, help="Minimal output.")
@option("--dry-run", is_flag=True, default=False, help="Just output unneeded packages.")
@verbose_option
@@ -620,11 +630,9 @@ def sync(
def clean(ctx, state, dry_run=False, bare=False, user=False):
"""Uninstalls all packages not specified in Pipfile.lock."""
from ..core import do_clean
do_clean(ctx=ctx, three=state.three, python=state.python, dry_run=dry_run)
do_clean(ctx=ctx, three=state.three, python=state.python, dry_run=dry_run,
system=state.system)
# Only invoke the "did you mean" when an argument wasn't passed (it breaks those).
if "-" not in "".join(sys.argv) and len(sys.argv) > 1:
cli = DYMCommandCollection(sources=[cli])
if __name__ == "__main__":
cli()
+22 -14
View File
@@ -4,18 +4,23 @@ from __future__ import absolute_import
import os
import click.types
from click import (
BadParameter, Group, Option, argument, echo, make_pass_decorator, option
)
from click_didyoumean import DYMMixin
from .. import environments
from ..utils import is_valid_url
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
CONTEXT_SETTINGS = {
"help_option_names": ["-h", "--help"],
"auto_envvar_prefix": "PIPENV"
}
class PipenvGroup(Group):
class PipenvGroup(DYMMixin, Group):
"""Custom Group class provides formatted main help"""
def get_help_option(self, ctx):
@@ -117,7 +122,7 @@ def sequential_option(f):
return value
return option("--sequential", is_flag=True, default=False, expose_value=False,
help="Install dependencies one-at-a-time, instead of concurrently.",
callback=callback, type=click.types.BOOL)(f)
callback=callback, type=click.types.BOOL, show_envvar=True)(f)
def skip_lock_option(f):
@@ -127,7 +132,8 @@ def skip_lock_option(f):
return value
return option("--skip-lock", is_flag=True, default=False, expose_value=False,
help=u"Skip locking mechanisms and use the Pipfile instead during operation.",
envvar="PIPENV_SKIP_LOCK", callback=callback, type=click.types.BOOL)(f)
envvar="PIPENV_SKIP_LOCK", callback=callback, type=click.types.BOOL,
show_envvar=True)(f)
def keep_outdated_option(f):
@@ -137,7 +143,7 @@ def keep_outdated_option(f):
return value
return option("--keep-outdated", is_flag=True, default=False, expose_value=False,
help=u"Keep out-dated dependencies from being updated in Pipfile.lock.",
callback=callback, type=click.types.BOOL)(f)
callback=callback, type=click.types.BOOL, show_envvar=True)(f)
def selective_upgrade_option(f):
@@ -157,7 +163,7 @@ def ignore_pipfile_option(f):
return value
return option("--ignore-pipfile", is_flag=True, default=False, expose_value=False,
help="Ignore Pipfile when installing, using the Pipfile.lock.",
callback=callback, type=click.types.BOOL)(f)
callback=callback, type=click.types.BOOL, show_envvar=True)(f)
def dev_option(f):
@@ -167,7 +173,7 @@ def dev_option(f):
return value
return option("--dev", "-d", is_flag=True, default=False, type=click.types.BOOL,
help="Install both develop and default packages.", callback=callback,
expose_value=False)(f)
expose_value=False, show_envvar=True)(f)
def pre_option(f):
@@ -208,7 +214,7 @@ def python_option(f):
return value
return option("--python", default=False, nargs=1, callback=callback,
help="Specify which version of Python virtualenv should use.",
expose_value=False)(f)
expose_value=False, allow_from_autoenv=False)(f)
def pypi_mirror_option(f):
@@ -238,7 +244,7 @@ def site_packages_option(f):
return value
return option("--site-packages", is_flag=True, default=False, type=click.types.BOOL,
help="Enable site-packages for the virtualenv.", callback=callback,
expose_value=False)(f)
expose_value=False, show_envvar=True)(f)
def clear_option(f):
@@ -248,7 +254,7 @@ def clear_option(f):
return value
return option("--clear", is_flag=True, callback=callback, type=click.types.BOOL,
help="Clears caches (pipenv, pip, and pip-tools).",
expose_value=False)(f)
expose_value=False, show_envvar=True)(f)
def system_option(f):
@@ -258,7 +264,8 @@ def system_option(f):
state.system = value
return value
return option("--system", is_flag=True, default=False, help="System pip management.",
callback=callback, type=click.types.BOOL, expose_value=False)(f)
callback=callback, type=click.types.BOOL, expose_value=False,
show_envvar=True)(f)
def requirementstxt_option(f):
@@ -287,8 +294,9 @@ def code_option(f):
if value:
state.installstate.code = value
return value
return option("--code", "-c", nargs=1, default=False, help="Import from codebase.",
callback=callback, expose_value=False)(f)
return option("--code", "-c", nargs=1, default=False, help="Install packages "
"automatically discovered from import statements.", callback=callback,
expose_value=False)(f)
def deploy_option(f):
@@ -298,7 +306,7 @@ def deploy_option(f):
return value
return option("--deploy", is_flag=True, default=False, type=click.types.BOOL,
help=u"Abort if the Pipfile.lock is out-of-date, or Python version is"
" wrong.", callback=callback, expose_value=False)(f)
" wrong.", callback=callback, expose_value=False)(f)
def setup_verbosity(ctx, param, value):
+17 -2
View File
@@ -70,14 +70,29 @@ class Script(object):
Foul characters include:
* Whitespaces.
* Carets (^). (pypa/pipenv#3307)
* Parentheses in the command. (pypa/pipenv#3168)
Carets introduce a difficult situation since they are essentially
"lossy" when parsed. Consider this in cmd.exe::
> echo "foo^bar"
"foo^bar"
> echo foo^^bar
foo^bar
The two commands produce different results, but are both parsed by the
shell as `foo^bar`, and there's essentially no sensible way to tell
what was actually passed in. This implementation assumes the quoted
variation (the first) since it is easier to implement, and arguably
the more common case.
The intended use of this function is to pre-process an argument list
before passing it into ``subprocess.Popen(..., shell=True)``.
See also: https://docs.python.org/3/library/subprocess.html#converting-argument-sequence
"""
return " ".join(itertools.chain(
[_quote_if_contains(self.command, r'[\s()]')],
(_quote_if_contains(arg, r'\s') for arg in self.args),
[_quote_if_contains(self.command, r'[\s^()]')],
(_quote_if_contains(arg, r'[\s^]') for arg in self.args),
))
+238 -138
View File
@@ -1,62 +1,42 @@
# -*- coding=utf-8 -*-
from __future__ import absolute_import, print_function
import json as simplejson
import logging
import os
import sys
import shutil
import sys
import time
import json as simplejson
import warnings
import click
import six
import urllib3.util as urllib3_util
from pipenv.vendor import vistir
import click_completion
import crayons
import dotenv
import delegator
import dotenv
import pipfile
import vistir
import warnings
import six
import urllib3.util as urllib3_util
from . import environments, exceptions, pep508checker, progress
from ._compat import fix_utf8, decode_for_output
from .cmdparse import Script
from .environments import (
PIPENV_CACHE_DIR, PIPENV_COLORBLIND, PIPENV_DEFAULT_PYTHON_VERSION,
PIPENV_DONT_USE_PYENV, PIPENV_HIDE_EMOJIS, PIPENV_MAX_SUBPROCESS,
PIPENV_PYUP_API_KEY, PIPENV_SHELL_FANCY, PIPENV_SKIP_VALIDATION,
PIPENV_YES, SESSION_IS_INTERACTIVE
)
from .project import Project, SourceNotFound
from .utils import (
convert_deps_to_pip,
is_required_version,
proper_case,
pep423_name,
venv_resolve_deps,
escape_grouped_arguments,
python_version,
find_windows_executable,
prepare_pip_source_args,
is_valid_url,
is_pypi_url,
create_mirror_source,
download_file,
is_pinned,
is_star,
parse_indexes,
escape_cmd,
create_spinner,
get_canonical_names
convert_deps_to_pip, create_mirror_source, create_spinner, download_file,
escape_cmd, escape_grouped_arguments, find_windows_executable,
get_canonical_names, is_pinned, is_pypi_url, is_required_version, is_star,
is_valid_url, parse_indexes, pep423_name, prepare_pip_source_args,
proper_case, python_version, venv_resolve_deps
)
from . import environments, pep508checker, progress
from .environments import (
PIPENV_COLORBLIND,
PIPENV_SHELL_FANCY,
PIPENV_SKIP_VALIDATION,
PIPENV_HIDE_EMOJIS,
PIPENV_YES,
PIPENV_DEFAULT_PYTHON_VERSION,
PIPENV_MAX_SUBPROCESS,
PIPENV_DONT_USE_PYENV,
SESSION_IS_INTERACTIVE,
PIPENV_CACHE_DIR,
PIPENV_PYUP_API_KEY,
)
from ._compat import fix_utf8
from . import exceptions
# Packages that should be ignored later.
BAD_PACKAGES = (
@@ -455,6 +435,11 @@ def ensure_python(three=None, python=None):
sp.ok(environments.PIPENV_SPINNER_OK_TEXT.format("Success!"))
# Print the results, in a beautiful blue…
click.echo(crayons.blue(c.out), err=True)
# Clear the pythonfinder caches
from .vendor.pythonfinder import Finder
finder = Finder(system=False, global_search=True)
finder.find_python_version.cache_clear()
finder.find_all_python_versions.cache_clear()
# Find the newly installed Python, hopefully.
version = str(version)
path_to_python = find_a_system_python(version)
@@ -690,10 +675,10 @@ def batch_install(deps_list, procs, failed_deps_queue,
requirements_dir, no_deps=False, ignore_hashes=False,
allow_global=False, blocking=False, pypi_mirror=None,
nprocs=PIPENV_MAX_SUBPROCESS, retry=True):
from .vendor.requirementslib.models.utils import strip_extras_markers_from_requirement
failed = (not retry)
if not failed:
label = INSTALL_LABEL if os.name != "nt" else ""
label = INSTALL_LABEL if not PIPENV_HIDE_EMOJIS else ""
else:
label = INSTALL_LABEL2
@@ -705,6 +690,10 @@ def batch_install(deps_list, procs, failed_deps_queue,
trusted_hosts = []
# Install these because
for dep in deps_list_bar:
if dep.req.req:
dep.req.req = strip_extras_markers_from_requirement(dep.req.req)
if dep.markers:
dep.markers = str(strip_extras_markers_from_requirement(dep.get_markers()))
index = None
if dep.index:
index = project.find_source(dep.index)
@@ -713,10 +702,18 @@ def batch_install(deps_list, procs, failed_deps_queue,
trusted_hosts.append(urllib3_util.parse_url(index.get("url")).host)
# Install the module.
is_artifact = False
if no_deps:
link = getattr(dep.req, "link", None)
is_wheel = False
if link:
is_wheel = link.is_wheel
if dep.is_file_or_url and (dep.is_direct_url or any(
dep.req.uri.endswith(ext) for ext in ["zip", "tar.gz"]
)):
is_artifact = True
elif dep.is_vcs:
is_artifact = True
needs_deps = not no_deps if no_deps is True else is_artifact
extra_indexes = []
if not index and indexes:
@@ -727,19 +724,28 @@ def batch_install(deps_list, procs, failed_deps_queue,
with vistir.contextmanagers.temp_environ():
if not allow_global:
os.environ["PIP_USER"] = vistir.compat.fs_str("0")
if "PYTHONHOME" in os.environ:
del os.environ["PYTHONHOME"]
if not needs_deps:
link = getattr(dep.req, "link", None)
is_wheel = False
if link:
is_wheel = link.is_wheel
needs_deps = dep.is_file_or_url and not (is_wheel or dep.editable)
c = pip_install(
dep,
ignore_hashes=any([ignore_hashes, dep.editable, dep.is_vcs]),
allow_global=allow_global,
no_deps=False if is_artifact else no_deps,
no_deps=not needs_deps,
block=any([dep.editable, dep.is_vcs, blocking]),
index=index,
requirements_dir=requirements_dir,
pypi_mirror=pypi_mirror,
trusted_hosts=trusted_hosts,
extra_indexes=extra_indexes
extra_indexes=extra_indexes,
use_pep517=not retry,
)
if dep.is_vcs:
if dep.is_vcs or dep.editable:
c.block()
if procs.qsize() < nprocs:
c.dep = dep
@@ -777,7 +783,8 @@ def do_install_dependencies(
click.echo(
crayons.normal(fix_utf8("Installing dependencies from Pipfile…"), bold=True)
)
lockfile = project.get_or_create_lockfile()
# skip_lock should completely bypass the lockfile (broken in 4dac1676)
lockfile = project.get_or_create_lockfile(from_pipfile=True)
else:
lockfile = project.get_or_create_lockfile()
if not bare:
@@ -807,6 +814,8 @@ def do_install_dependencies(
procs = queue.Queue(maxsize=PIPENV_MAX_SUBPROCESS)
failed_deps_queue = queue.Queue()
if skip_lock:
ignore_hashes = True
install_kwargs = {
"no_deps": no_deps, "ignore_hashes": ignore_hashes, "allow_global": allow_global,
@@ -817,6 +826,7 @@ def do_install_dependencies(
else:
install_kwargs["nprocs"] = 1
# with project.environment.activated():
batch_install(
deps_list, procs, failed_deps_queue, requirements_dir, **install_kwargs
)
@@ -1019,9 +1029,12 @@ def do_lock(
dev_packages = overwrite_dev(project.packages, dev_packages)
# Resolve dev-package dependencies, with pip-tools.
for is_dev in [True, False]:
pipfile_section = "dev_packages" if is_dev else "packages"
pipfile_section = "dev-packages" if is_dev else "packages"
lockfile_section = "develop" if is_dev else "default"
packages = getattr(project, pipfile_section)
if project.pipfile_exists:
packages = project.parsed_pipfile.get(pipfile_section, {})
else:
packages = getattr(project, pipfile_section.replace("-", "_"))
if write:
# Alert the user of progress.
@@ -1034,12 +1047,8 @@ def do_lock(
err=True,
)
deps = convert_deps_to_pip(
packages, project, r=False, include_index=True
)
# Mutates the lockfile
venv_resolve_deps(
deps,
packages,
which=which,
project=project,
dev=is_dev,
@@ -1189,9 +1198,9 @@ def do_init(
)
else:
if old_hash:
msg = fix_utf8("Pipfile.lock ({1}) out of date, updating to ({0})…")
msg = fix_utf8("Pipfile.lock ({0}) out of date, updating to ({1})…")
else:
msg = fix_utf8("Pipfile.lock is corrupted, replaced with ({0})…")
msg = fix_utf8("Pipfile.lock is corrupted, replaced with ({1})…")
click.echo(
crayons.red(msg.format(old_hash[-6:], new_hash[-6:]), bold=True),
err=True,
@@ -1260,12 +1269,12 @@ def pip_install(
requirements_dir=None,
extra_indexes=None,
pypi_mirror=None,
trusted_hosts=None
trusted_hosts=None,
use_pep517=True
):
from pipenv.patched.notpip._internal import logger as piplogger
from .utils import Mapping
from .vendor.vistir.compat import Mapping
from .vendor.urllib3.util import parse_url
src = []
write_to_tmpfile = False
if requirement:
@@ -1283,6 +1292,10 @@ def pip_install(
crayons.normal("Installing {0!r}".format(requirement.name), bold=True),
err=True,
)
if requirement:
ignore_hashes = True if not requirement.hashes else ignore_hashes
# Create files for hash mode.
if write_to_tmpfile:
if not requirements_dir:
@@ -1292,12 +1305,13 @@ def pip_install(
prefix="pipenv-", suffix="-requirement.txt", dir=requirements_dir,
delete=False
)
f.write(vistir.misc.to_bytes(requirement.as_line()))
line = requirement.as_line(include_hashes=not ignore_hashes)
f.write(vistir.misc.to_bytes(line))
r = f.name
f.close()
# Install dependencies when a package is a VCS dependency.
if requirement and requirement.vcs:
no_deps = False
# Install dependencies when a package is a non-editable VCS dependency.
# Don't specify a source directory when using --system.
if not allow_global and ("PIP_SRC" not in os.environ):
src.extend(["--src", "{0}".format(project.virtualenv_src_location)])
@@ -1343,25 +1357,84 @@ def pip_install(
create_mirror_source(pypi_mirror) if is_pypi_url(source["url"]) else source
for source in sources
]
line_kwargs = {"as_list": True, "include_hashes": not ignore_hashes}
# Install dependencies when a package is a VCS dependency.
if requirement and requirement.vcs:
ignore_hashes = True
# Don't specify a source directory when using --system.
src_dir = None
if "PIP_SRC" in os.environ:
src_dir = os.environ["PIP_SRC"]
src = ["--src", os.environ["PIP_SRC"]]
if not requirement.editable:
no_deps = False
if src_dir is not None:
repo = requirement.req.get_vcs_repo(src_dir=src_dir)
else:
repo = requirement.req.get_vcs_repo()
write_to_tmpfile = True
line_kwargs["include_markers"] = False
line_kwargs["include_hashes"] = False
if not requirements_dir:
requirements_dir = vistir.path.create_tracked_tempdir(prefix="pipenv",
suffix="requirements")
f = vistir.compat.NamedTemporaryFile(
prefix="pipenv-", suffix="-requirement.txt", dir=requirements_dir,
delete=False
)
line = "-e" if requirement.editable else ""
if requirement.editable or requirement.name is not None:
name = requirement.name
if requirement.extras:
name = "{0}{1}".format(name, requirement.extras_as_pip)
line = "-e {0}#egg={1}".format(vistir.path.path_to_url(repo.checkout_directory), requirement.name)
if repo.subdirectory:
line = "{0}&subdirectory={1}".format(line, repo.subdirectory)
else:
line = requirement.as_line(**line_kwargs)
f.write(vistir.misc.to_bytes(line))
r = f.name
f.close()
# Create files for hash mode.
if write_to_tmpfile and not r:
if not requirements_dir:
requirements_dir = vistir.path.create_tracked_tempdir(
prefix="pipenv", suffix="requirements")
f = vistir.compat.NamedTemporaryFile(
prefix="pipenv-", suffix="-requirement.txt", dir=requirements_dir,
delete=False
)
ignore_hashes = True if not requirement.hashes else ignore_hashes
line = requirement.as_line(include_hashes=not ignore_hashes)
line = "{0} {1}".format(line, " ".join(src))
f.write(vistir.misc.to_bytes(line))
r = f.name
f.close()
if (requirement and requirement.editable) and not r:
line_kwargs = {"as_list": True}
if requirement.markers:
line_kwargs["include_markers"] = False
line_kwargs["include_markers"] = False
line_kwargs["include_hashes"] = False
install_reqs = requirement.as_line(**line_kwargs)
if requirement.editable and install_reqs[0].startswith("-e "):
req, install_reqs = install_reqs[0], install_reqs[1:]
possible_hashes = install_reqs[:]
editable_opt, req = req.split(" ", 1)
install_reqs = [editable_opt, req] + install_reqs
if not all(item.startswith("--hash") for item in install_reqs):
ignore_hashes = True
# hashes must be passed via a file
ignore_hashes = True
elif r:
install_reqs = ["-r", r]
with open(r) as f:
if "--hash" not in f.read():
ignore_hashes = True
else:
ignore_hashes = True if not requirement.hashes else False
install_reqs = requirement.as_line(as_list=True)
ignore_hashes = True
install_reqs = requirement.as_line(as_list=True, include_hashes=not ignore_hashes)
if not requirement.markers:
install_reqs = [escape_cmd(r) for r in install_reqs]
elif len(install_reqs) > 1:
@@ -1382,7 +1455,11 @@ def pip_install(
pip_command.extend(prepare_pip_source_args(sources))
if not ignore_hashes:
pip_command.append("--require-hashes")
if not use_pep517:
from .vendor.packaging.version import parse as parse_version
pip_command.append("--no-build-isolation")
if project.environment.pip_version >= parse_version("19.0"):
pip_command.append("--no-use-pep517")
if environments.is_verbose():
click.echo("$ {0}".format(pip_command), err=True)
cache_dir = vistir.compat.Path(PIPENV_CACHE_DIR)
@@ -1401,6 +1478,8 @@ def pip_install(
)
cmd = Script.parse(pip_command)
pip_command = cmd.cmdify()
c = None
# with project.environment.activated():
c = delegator.run(pip_command, block=block, env=pip_config)
return c
@@ -1712,14 +1791,8 @@ def do_install(
# Don't search for requirements.txt files if the user provides one
if requirements or package_args or project.pipfile_exists:
skip_requirements = True
# Don't attempt to install develop and default packages if Pipfile is missing
if not project.pipfile_exists and not (package_args or dev) and not code:
if not (ignore_pipfile or deploy):
raise exceptions.PipfileNotFound(project.path_to("Pipfile"))
elif ((skip_lock and deploy) or ignore_pipfile) and not project.lockfile_exists:
raise exceptions.LockfileNotFound(project.path_to("Pipfile.lock"))
concurrent = not sequential
# Ensure that virtualenv is available.
# Ensure that virtualenv is available and pipfile are available
ensure_project(
three=three,
python=python,
@@ -1729,6 +1802,12 @@ def do_install(
skip_requirements=skip_requirements,
pypi_mirror=pypi_mirror,
)
# Don't attempt to install develop and default packages if Pipfile is missing
if not project.pipfile_exists and not (package_args or dev) and not code:
if not (ignore_pipfile or deploy):
raise exceptions.PipfileNotFound(project.path_to("Pipfile"))
elif ((skip_lock and deploy) or ignore_pipfile) and not project.lockfile_exists:
raise exceptions.LockfileNotFound(project.path_to("Pipfile.lock"))
# Load the --pre settings from the Pipfile.
if not pre:
pre = project.settings.get("allow_prereleases")
@@ -1814,26 +1893,6 @@ def do_install(
for req in import_from_code(code):
click.echo(" Found {0}!".format(crayons.green(req)))
project.add_package_to_pipfile(req)
# Install editable local packages before locking - this gives us access to dist-info
if project.pipfile_exists and (
# double negatives are for english readability, leave them alone.
(not project.lockfile_exists and not deploy)
or (not project.virtualenv_exists and not system)
):
section = (
project.editable_packages if not dev else project.editable_dev_packages
)
for package in section.keys():
req = convert_deps_to_pip(
{package: section[package]}, project=project, r=False
)
if req:
req = req[0]
req = req[len("-e ") :] if req.startswith("-e ") else req
if not editable_packages:
editable_packages = [req]
else:
editable_packages.extend([req])
# Allow more than one package to be provided.
package_args = [p for p in packages] + [
"-e {0}".format(pkg) for pkg in editable_packages
@@ -1852,7 +1911,7 @@ def do_install(
if not is_star(section[package__name]) and is_star(package__val):
# Support for VCS dependencies.
package_args[i] = convert_deps_to_pip(
{packages: section[package__name]}, project=project, r=False
{package__name: section[package__name]}, project=project, r=False
)[0]
except KeyError:
pass
@@ -1877,9 +1936,9 @@ def do_install(
keep_outdated=keep_outdated
)
# This is for if the user passed in dependencies, then we want to maek sure we
# This is for if the user passed in dependencies, then we want to make sure we
else:
from .vendor.requirementslib import Requirement
from .vendor.requirementslib.models.requirements import Requirement
# make a tuple of (display_name, entry)
pkg_list = packages + ["-e {0}".format(pkg) for pkg in editable_packages]
@@ -1906,6 +1965,8 @@ def do_install(
with vistir.contextmanagers.temp_environ(), create_spinner("Installing...") as sp:
if not system:
os.environ["PIP_USER"] = vistir.compat.fs_str("0")
if "PYTHONHOME" in os.environ:
del os.environ["PYTHONHOME"]
try:
pkg_requirement = Requirement.from_line(pkg_line)
except ValueError as e:
@@ -1927,6 +1988,17 @@ def do_install(
extra_indexes=extra_index_url,
pypi_mirror=pypi_mirror,
)
if not c.ok:
sp.write_err(vistir.compat.fs_str(
"{0}: {1}".format(
crayons.red("WARNING"),
"Failed installing package {0}".format(pkg_line)
),
))
sp.write_err(vistir.compat.fs_str(
"Error text: {0}".format(c.out)
))
raise RuntimeError(c.err)
except (ValueError, RuntimeError) as e:
sp.write_err(vistir.compat.fs_str(
"{0}: {1}".format(crayons.red("WARNING"), e),
@@ -1934,6 +2006,7 @@ def do_install(
sp.fail(environments.PIPENV_SPINNER_FAIL_TEXT.format(
"Installation Failed",
))
sys.exit(1)
# Warn if --editable wasn't passed.
if pkg_requirement.is_vcs and not pkg_requirement.editable:
sp.write_err(
@@ -1972,12 +2045,20 @@ def do_install(
crayons.normal(fix_utf8(""), bold=True),
)
))
# Add the package to the Pipfile.
try:
project.add_package_to_pipfile(pkg_requirement, dev)
except ValueError as e:
import traceback
sp.write_err(
"{0} {1}".format(
crayons.red("Error:", bold=True), traceback.format_exc()
)
)
sp.fail(environments.PIPENV_SPINNER_FAIL_TEXT.format(
"Failed adding package to Pipfile"
))
sp.ok(environments.PIPENV_SPINNER_OK_TEXT.format("Installation Succeeded"))
# Add the package to the Pipfile.
try:
project.add_package_to_pipfile(pkg_requirement, dev)
except ValueError as e:
raise exceptions.PipfileException(e)
# Update project settings with pre preference.
if pre:
project.update_settings({"allow_prereleases": pre})
@@ -2157,11 +2238,6 @@ def do_shell(three=None, python=False, fancy=False, shell_args=None, pypi_mirror
three=three, python=python, validate=False, pypi_mirror=pypi_mirror,
)
# Set an environment variable, so we know we're in the environment.
os.environ["PIPENV_ACTIVE"] = vistir.misc.fs_str("1")
os.environ.pop("PIP_SHIMS_BASE_MODULE", None)
# Support shell compatibility mode.
if PIPENV_SHELL_FANCY:
fancy = True
@@ -2177,6 +2253,13 @@ def do_shell(three=None, python=False, fancy=False, shell_args=None, pypi_mirror
shell_args,
)
# Set an environment variable, so we know we're in the environment.
# Only set PIPENV_ACTIVE after finishing reading virtualenv_location
# otherwise its value will be changed
os.environ["PIPENV_ACTIVE"] = vistir.misc.fs_str("1")
os.environ.pop("PIP_SHIMS_BASE_MODULE", None)
if fancy:
shell.fork(*fork_args)
return
@@ -2311,22 +2394,42 @@ def do_run(command, args, three=None, python=False, pypi_mirror=None):
three=three, python=python, validate=False, pypi_mirror=pypi_mirror,
)
# Set an environment variable, so we know we're in the environment.
os.environ["PIPENV_ACTIVE"] = vistir.misc.fs_str("1")
os.environ.pop("PIP_SHIMS_BASE_MODULE", None)
load_dot_env()
previous_pip_shims_module = os.environ.pop("PIP_SHIMS_BASE_MODULE", None)
# Activate virtualenv under the current interpreter's environment
inline_activate_virtual_environment()
# Set an environment variable, so we know we're in the environment.
# Only set PIPENV_ACTIVE after finishing reading virtualenv_location
# such as in inline_activate_virtual_environment
# otherwise its value will be changed
previous_pipenv_active_value = os.environ.get("PIPENV_ACTIVE")
os.environ["PIPENV_ACTIVE"] = vistir.misc.fs_str("1")
try:
script = project.build_script(command, args)
cmd_string = ' '.join([script.command] + script.args)
if environments.is_verbose():
click.echo(crayons.normal("$ {0}".format(cmd_string)), err=True)
except ScriptEmptyError:
click.echo("Can't run script {0!r}-it's empty?", err=True)
run_args = [script]
run_kwargs = {}
if os.name == "nt":
do_run_nt(script)
run_fn = do_run_nt
else:
do_run_posix(script, command=command)
run_fn = do_run_posix
run_kwargs = {"command": command}
try:
run_fn(*run_args, **run_kwargs)
finally:
os.environ.pop("PIPENV_ACTIVE", None)
if previous_pipenv_active_value is not None:
os.environ["PIPENV_ACTIVE"] = previous_pipenv_active_value
if previous_pip_shims_module is not None:
os.environ["PIP_SHIMS_BASE_MODULE"] = previous_pip_shims_module
def do_check(
@@ -2506,7 +2609,7 @@ def do_graph(bare=False, json=False, json_tree=False, reverse=False):
if not project.virtualenv_exists:
click.echo(
u"{0}: No virtualenv has been created for this project yet! Consider "
u"running {1} first to automatically generate one for you or see"
u"running {1} first to automatically generate one for you or see "
u"{2} for further instructions.".format(
crayons.red("Warning", bold=True),
crayons.green("`pipenv install`"),
@@ -2587,7 +2690,7 @@ def do_sync(
):
# The lock file needs to exist because sync won't write to it.
if not project.lockfile_exists:
raise exceptions.LockfileNotFound(project.lockfile_location)
raise exceptions.LockfileNotFound("Pipfile.lock")
# Ensure that virtualenv is available if not system.
ensure_project(
@@ -2615,34 +2718,32 @@ def do_sync(
click.echo(crayons.green("All dependencies are now up-to-date!"))
def do_clean(ctx, three=None, python=None, dry_run=False, bare=False, pypi_mirror=None):
def do_clean(
ctx, three=None, python=None, dry_run=False, bare=False, pypi_mirror=None,
system=False
):
# Ensure that virtualenv is available.
from packaging.utils import canonicalize_name
ensure_project(three=three, python=python, validate=False, pypi_mirror=pypi_mirror)
ensure_lockfile(pypi_mirror=pypi_mirror)
# Make sure that the virtualenv's site packages are configured correctly
# otherwise we may end up removing from the global site packages directory
installed_package_names = [
canonicalize_name(pkg.project_name) for pkg
in project.environment.get_installed_packages()
]
installed_package_names = project.installed_package_names.copy()
# Remove known "bad packages" from the list.
for bad_package in BAD_PACKAGES:
if canonicalize_name(bad_package) in installed_package_names:
if environments.is_verbose():
click.echo("Ignoring {0}.".format(bad_package), err=True)
del installed_package_names[installed_package_names.index(
canonicalize_name(bad_package)
)]
installed_package_names.remove(canonicalize_name(bad_package))
# Intelligently detect if --dev should be used or not.
develop = [canonicalize_name(k) for k in project.lockfile_content["develop"].keys()]
default = [canonicalize_name(k) for k in project.lockfile_content["default"].keys()]
for used_package in set(develop + default):
locked_packages = {
canonicalize_name(pkg) for pkg in project.lockfile_package_names["combined"]
}
for used_package in locked_packages:
if used_package in installed_package_names:
del installed_package_names[installed_package_names.index(
canonicalize_name(used_package)
)]
installed_package_names.remove(used_package)
failure = False
cmd = [which_pip(allow_global=system), "uninstall", "-y", "-qq"]
for apparent_bad_package in installed_package_names:
if dry_run and not bare:
click.echo(apparent_bad_package)
@@ -2654,9 +2755,8 @@ def do_clean(ctx, three=None, python=None, dry_run=False, bare=False, pypi_mirro
)
)
# Uninstall the package.
c = delegator.run(
"{0} uninstall {1} -y".format(which_pip(), apparent_bad_package)
)
cmd_str = Script.parse(cmd + [apparent_bad_package]).cmdify()
c = delegator.run(cmd_str, block=True)
if c.return_code != 0:
failure = True
sys.exit(int(failure))
+76 -28
View File
@@ -3,22 +3,25 @@
import contextlib
import importlib
import json
import os
import sys
import operator
import pkg_resources
import os
import site
import six
import sys
from distutils.sysconfig import get_python_lib
from sysconfig import get_paths
from cached_property import cached_property
import itertools
import pkg_resources
import six
import vistir
import pipenv
from .utils import normalize_path
from .vendor.cached_property import cached_property
import vistir
from .utils import normalize_path, make_posix
BASE_WORKING_SET = pkg_resources.WorkingSet(sys.path)
@@ -90,12 +93,16 @@ class Environment(object):
deps |= cls.resolve_dist(dist, working_set)
return deps
def add_dist(self, dist_name):
dist = pkg_resources.get_distribution(pkg_resources.Requirement(dist_name))
def extend_dists(self, dist):
extras = self.resolve_dist(dist, self.base_working_set)
self.extra_dists.append(dist)
if extras:
self.extra_dists.extend(extras)
def add_dist(self, dist_name):
dist = pkg_resources.get_distribution(pkg_resources.Requirement(dist_name))
self.extend_dists(dist)
@cached_property
def python_version(self):
with self.activated():
@@ -143,7 +150,7 @@ class Environment(object):
'stdlib': '/home/hawk/.pyenv/versions/3.7.1/lib/python3.7'}
"""
prefix = self.prefix.as_posix()
prefix = make_posix(self.prefix.as_posix())
install_scheme = 'nt' if (os.name == 'nt') else 'posix_prefix'
paths = get_paths(install_scheme, vars={
'base': prefix,
@@ -152,8 +159,8 @@ class Environment(object):
paths["PATH"] = paths["scripts"] + os.pathsep + os.defpath
if "prefix" not in paths:
paths["prefix"] = prefix
purelib = get_python_lib(plat_specific=0, prefix=prefix)
platlib = get_python_lib(plat_specific=1, prefix=prefix)
purelib = make_posix(get_python_lib(plat_specific=0, prefix=prefix))
platlib = make_posix(get_python_lib(plat_specific=1, prefix=prefix))
if purelib == platlib:
lib_dirs = purelib
else:
@@ -161,7 +168,7 @@ class Environment(object):
paths["libdir"] = purelib
paths["purelib"] = purelib
paths["platlib"] = platlib
paths['PYTHONPATH'] = lib_dirs
paths['PYTHONPATH'] = os.pathsep.join(["", ".", lib_dirs])
paths["libdirs"] = lib_dirs
return paths
@@ -174,19 +181,21 @@ class Environment(object):
@property
def python(self):
"""Path to the environment python"""
py = vistir.compat.Path(self.base_paths["scripts"]).joinpath("python").as_posix()
py = vistir.compat.Path(self.base_paths["scripts"]).joinpath("python").absolute().as_posix()
if not py:
return vistir.compat.Path(sys.executable).as_posix()
return py
@cached_property
def sys_path(self):
"""The system path inside the environment
"""
The system path inside the environment
:return: The :data:`sys.path` from the environment
:rtype: list
"""
from .vendor.vistir.compat import JSONDecodeError
current_executable = vistir.compat.Path(sys.executable).as_posix()
if not self.python or self.python == current_executable:
return sys.path
@@ -194,12 +203,16 @@ class Environment(object):
return sys.path
cmd_args = [self.python, "-c", "import json, sys; print(json.dumps(sys.path))"]
path, _ = vistir.misc.run(cmd_args, return_object=False, nospin=True, block=True, combine_stderr=False, write_to_stdout=False)
path = json.loads(path.strip())
try:
path = json.loads(path.strip())
except JSONDecodeError:
path = sys.path
return path
@cached_property
def sys_prefix(self):
"""The prefix run inside the context of the environment
"""
The prefix run inside the context of the environment
:return: The python prefix inside the environment
:rtype: :data:`sys.prefix`
@@ -234,15 +247,33 @@ class Environment(object):
return "purelib", purelib
return "platlib", self.paths["platlib"]
@property
def pip_version(self):
"""
Get the pip version in the environment. Useful for knowing which args we can use
when installing.
"""
from .vendor.packaging.version import parse as parse_version
pip = next(iter(
pkg for pkg in self.get_installed_packages() if pkg.key == "pip"
), None)
if pip is not None:
pip_version = parse_version(pip.version)
return parse_version("18.0")
def get_distributions(self):
"""Retrives the distributions installed on the library path of the environment
"""
Retrives the distributions installed on the library path of the environment
:return: A set of distributions found on the library path
:rtype: iterator
"""
pkg_resources = self.safe_import("pkg_resources")
return pkg_resources.find_distributions(self.paths["PYTHONPATH"])
libdirs = self.base_paths["libdirs"].split(os.pathsep)
dists = (pkg_resources.find_distributions(libdir) for libdir in libdirs)
for dist in itertools.chain.from_iterable(dists):
yield dist
def find_egg(self, egg_dist):
"""Find an egg by name in the given environment"""
@@ -269,21 +300,28 @@ class Environment(object):
def dist_is_in_project(self, dist):
"""Determine whether the supplied distribution is in the environment."""
from .project import _normalized
prefix = _normalized(self.base_paths["prefix"])
prefixes = [
_normalized(prefix) for prefix in self.base_paths["libdirs"].split(os.pathsep)
if _normalized(prefix).startswith(_normalized(self.prefix.as_posix()))
]
location = self.locate_dist(dist)
if not location:
return False
return _normalized(location).startswith(prefix)
location = _normalized(make_posix(location))
return any(location.startswith(prefix) for prefix in prefixes)
def get_installed_packages(self):
"""Returns all of the installed packages in a given environment"""
workingset = self.get_working_set()
packages = [pkg for pkg in workingset if self.dist_is_in_project(pkg)]
packages = [
pkg for pkg in workingset
if self.dist_is_in_project(pkg) and pkg.key != "python"
]
return packages
@contextlib.contextmanager
def get_finder(self, pre=False):
from .vendor.pip_shims import Command, cmdoptions, index_group, PackageFinder
from .vendor.pip_shims.shims import Command, cmdoptions, index_group, PackageFinder
from .environments import PIPENV_CACHE_DIR
index_urls = [source.get("url") for source in self.sources]
@@ -473,6 +511,7 @@ class Environment(object):
vendor_dir = parent_path.joinpath("vendor").as_posix()
patched_dir = parent_path.joinpath("patched").as_posix()
parent_path = parent_path.as_posix()
self.add_dist("pip")
prefix = self.prefix.as_posix()
with vistir.contextmanagers.temp_environ(), vistir.contextmanagers.temp_path():
os.environ["PATH"] = os.pathsep.join([
@@ -482,12 +521,24 @@ class Environment(object):
])
os.environ["PYTHONIOENCODING"] = vistir.compat.fs_str("utf-8")
os.environ["PYTHONDONTWRITEBYTECODE"] = vistir.compat.fs_str("1")
os.environ["PYTHONPATH"] = self.base_paths["PYTHONPATH"]
from .environments import PIPENV_USE_SYSTEM
if self.is_venv:
os.environ["PYTHONPATH"] = self.base_paths["PYTHONPATH"]
os.environ["VIRTUAL_ENV"] = vistir.compat.fs_str(prefix)
else:
if not PIPENV_USE_SYSTEM and not os.environ.get("VIRTUAL_ENV"):
os.environ["PYTHONPATH"] = self.base_paths["PYTHONPATH"]
os.environ.pop("PYTHONHOME", None)
sys.path = self.sys_path
sys.prefix = self.sys_prefix
site.addsitedir(self.base_paths["purelib"])
pip = self.safe_import("pip")
pip_vendor = self.safe_import("pip._vendor")
pep517_dir = os.path.join(os.path.dirname(pip_vendor.__file__), "pep517")
site.addsitedir(pep517_dir)
os.environ["PYTHONPATH"] = os.pathsep.join([
os.environ.get("PYTHONPATH", self.base_paths["PYTHONPATH"]), pep517_dir
])
if include_extras:
site.addsitedir(parent_path)
sys.path.extend([parent_path, patched_dir, vendor_dir])
@@ -591,10 +642,7 @@ class Environment(object):
monkey_patch.activate()
pip_shims = self.safe_import("pip_shims")
pathset_base = pip_shims.UninstallPathSet
import recursive_monkey_patch
recursive_monkey_patch.monkey_patch(
PatchedUninstaller, pathset_base
)
pathset_base._permitted = PatchedUninstaller._permitted
dist = next(
iter(filter(lambda d: d.project_name == pkgname, self.get_working_set())),
None
+53 -15
View File
@@ -2,15 +2,26 @@
import os
import sys
from appdirs import user_cache_dir
from .vendor.vistir.misc import fs_str
from ._compat import fix_utf8
from .vendor.vistir.misc import fs_str
# HACK: avoid resolver.py uses the wrong byte code files.
# I hope I can remove this one day.
os.environ["PYTHONDONTWRITEBYTECODE"] = fs_str("1")
def _is_env_truthy(name):
"""An environment variable is truthy if it exists and isn't one of (0, false, no, off)
"""
if name not in os.environ:
return False
return os.environ.get(name).lower() not in ("0", "false", "no", "off")
PIPENV_IS_CI = bool("CI" in os.environ or "TF_BUILD" in os.environ)
# HACK: Prevent invalid shebangs with Homebrew-installed Python:
@@ -68,13 +79,15 @@ Default is to detect emulators automatically. This should be set if your
emulator, e.g. Cmder, cannot be detected correctly.
"""
PIPENV_HIDE_EMOJIS = bool(os.environ.get("PIPENV_HIDE_EMOJIS"))
PIPENV_HIDE_EMOJIS = (
os.environ.get("PIPENV_HIDE_EMOJIS") is None
and (os.name == "nt" or PIPENV_IS_CI)
or _is_env_truthy("PIPENV_HIDE_EMOJIS")
)
"""Disable emojis in output.
Default is to show emojis. This is automatically set on Windows.
"""
if os.name == "nt" or PIPENV_IS_CI:
PIPENV_HIDE_EMOJIS = True
PIPENV_IGNORE_VIRTUALENVS = bool(os.environ.get("PIPENV_IGNORE_VIRTUALENVS"))
"""If set, Pipenv will always assign a virtual environment for this project.
@@ -97,10 +110,9 @@ PIPENV_MAX_DEPTH = int(os.environ.get("PIPENV_MAX_DEPTH", "3")) + 1
Default is 3. See also ``PIPENV_NO_INHERIT``.
"""
PIPENV_MAX_RETRIES = int(os.environ.get(
"PIPENV_MAX_RETRIES",
"1" if PIPENV_IS_CI else "0",
))
PIPENV_MAX_RETRIES = int(
os.environ.get("PIPENV_MAX_RETRIES", "1" if PIPENV_IS_CI else "0")
)
"""Specify how many retries Pipenv should attempt for network requests.
Default is 0. Automatically set to 1 on CI environments for robust testing.
@@ -222,7 +234,9 @@ Default is to lock dependencies and update ``Pipfile.lock`` on each run.
NOTE: This only affects the ``install`` and ``uninstall`` commands.
"""
PIPENV_PYUP_API_KEY = os.environ.get("PIPENV_PYUP_API_KEY", "1ab8d58f-5122e025-83674263-bc1e79e0")
PIPENV_PYUP_API_KEY = os.environ.get(
"PIPENV_PYUP_API_KEY", "1ab8d58f-5122e025-83674263-bc1e79e0"
)
# Internal, support running in a different Python from sys.executable.
PIPENV_PYTHON = os.environ.get("PIPENV_PYTHON")
@@ -243,9 +257,9 @@ PIPENV_SKIP_VALIDATION = True
# Internal, the default shell to use if shell detection fails.
PIPENV_SHELL = (
os.environ.get("SHELL") or
os.environ.get("PYENV_SHELL") or
os.environ.get("COMSPEC")
os.environ.get("SHELL")
or os.environ.get("PYENV_SHELL")
or os.environ.get("COMSPEC")
)
# Internal, to tell whether the command line session is interactive.
@@ -277,11 +291,35 @@ def is_quiet(threshold=-1):
def is_in_virtualenv():
pipenv_active = os.environ.get("PIPENV_ACTIVE")
virtual_env = os.environ.get("VIRTUAL_ENV")
return (PIPENV_USE_SYSTEM or virtual_env) and not pipenv_active
"""
Check virtualenv membership dynamically
:return: True or false depending on whether we are in a regular virtualenv or not
:rtype: bool
"""
pipenv_active = os.environ.get("PIPENV_ACTIVE", False)
virtual_env = None
use_system = False
ignore_virtualenvs = bool(os.environ.get("PIPENV_IGNORE_VIRTUALENVS", False))
if not pipenv_active and not ignore_virtualenvs:
virtual_env = os.environ.get("VIRTUAL_ENV")
use_system = bool(virtual_env)
return (use_system or virtual_env) and not (pipenv_active or ignore_virtualenvs)
PIPENV_SPINNER_FAIL_TEXT = fix_utf8(u"{0}") if not PIPENV_HIDE_EMOJIS else ("{0}")
PIPENV_SPINNER_OK_TEXT = fix_utf8(u"{0}") if not PIPENV_HIDE_EMOJIS else ("{0}")
def is_type_checking():
try:
from typing import TYPE_CHECKING
except ImportError:
return False
return TYPE_CHECKING
MYPY_RUNNING = is_type_checking()
+20 -19
View File
@@ -3,27 +3,21 @@
import itertools
import sys
from traceback import format_exception
from pprint import pformat
from traceback import format_exception, format_tb
import six
from . import environments
from ._compat import fix_utf8
from .patched import crayons
from . import environments
from .vendor.click.utils import echo as click_echo
from .vendor.click._compat import get_text_stderr
from .vendor.click.exceptions import (
Abort,
BadOptionUsage,
BadParameter,
ClickException,
Exit,
FileError,
MissingParameter,
UsageError,
Abort, BadOptionUsage, BadParameter, ClickException, Exit, FileError,
MissingParameter, UsageError
)
from .vendor.click.types import Path
from .vendor.click.utils import echo as click_echo
def handle_exception(exc_type, exception, traceback, hook=sys.excepthook):
@@ -31,8 +25,8 @@ def handle_exception(exc_type, exception, traceback, hook=sys.excepthook):
hook(exc_type, exception, traceback)
else:
exc = format_exception(exc_type, exception, traceback)
lines = itertools.chain.from_iterable([l.splitlines() for l in exc])
lines = list(lines)[-11:-1]
tb = format_tb(traceback, limit=-6)
lines = itertools.chain.from_iterable([frame.splitlines() for frame in tb])
for line in lines:
line = line.strip("'").strip('"').strip("\n").strip()
if not line.startswith("File"):
@@ -165,7 +159,7 @@ class DeployException(PipenvUsageError):
if not message:
message = crayons.normal("Aborting deploy", bold=True)
extra = kwargs.pop("extra", [])
PipenvUsageError.__init__(message=fix_utf8(message), extra=extra, **kwargs)
PipenvUsageError.__init__(self, message=fix_utf8(message), extra=extra, **kwargs)
class PipenvOptionsError(PipenvUsageError):
@@ -185,7 +179,8 @@ class SystemUsageError(PipenvOptionsError):
crayons.red("Warning", bold=True)
),
]
message = crayons.blue("See also: {0}".format(crayons.white("-deploy flag.")))
if message is None:
message = crayons.blue("See also: {0}".format(crayons.white("--deploy flag.")))
super(SystemUsageError, self).__init__(option_name, message=message, ctx=ctx, extra=extra, **kwargs)
@@ -241,11 +236,11 @@ class UninstallError(PipenvException):
crayons.yellow("$ {0}".format(command), bold=True)
)),]
extra.extend([crayons.blue(line.strip()) for line in return_values.splitlines()])
if isinstance(package, (tuple, list)):
if isinstance(package, (tuple, list, set)):
package = " ".join(package)
message = "{0} {1}...".format(
message = "{0!s} {1!s}...".format(
crayons.normal("Failed to uninstall package(s)"),
crayons.yellow(package, bold=True)
crayons.yellow(str(package), bold=True)
)
self.exit_code = return_code
PipenvException.__init__(self, message=fix_utf8(message), extra=extra)
@@ -254,8 +249,14 @@ class UninstallError(PipenvException):
class InstallError(PipenvException):
def __init__(self, package, **kwargs):
message = "{0} {1}".format(
package_message = ""
if package is not None:
package_message = crayons.normal("Couldn't install package {0}\n".format(
crayons.white(package, bold=True)
))
message = "{0} {1} {2}".format(
crayons.red("ERROR:", bold=True),
package_message,
crayons.yellow("Package installation failed...")
)
extra = kwargs.pop("extra", [])
+1 -1
View File
@@ -2,4 +2,4 @@
__author__ = """pyup.io"""
__email__ = 'support@pyup.io'
__version__ = '1.8.4'
__version__ = '1.8.5'
+68 -26
View File
@@ -6,17 +6,13 @@ from safety import __version__
from safety import safety
from safety.formatter import report
import itertools
from safety.util import read_requirements
from safety.util import read_requirements, read_vulnerabilities
from safety.errors import DatabaseFetchError, DatabaseFileNotFoundError, InvalidKeyError
try:
# pip 9
from pipenv.patched.notpip import get_installed_distributions
from json.decoder import JSONDecodeError
except ImportError:
# pip 10
from pipenv.patched.notpip._internal.utils.misc import get_installed_distributions
JSONDecodeError = ValueError
@click.group()
@click.version_option(version=__version__)
@@ -46,10 +42,17 @@ def cli():
help="Read input from one (or multiple) requirement files. Default: empty")
@click.option("ignore", "--ignore", "-i", multiple=True, type=str, default=[],
help="Ignore one (or multiple) vulnerabilities by ID. Default: empty")
def check(key, db, json, full_report, bare, stdin, files, cache, ignore):
@click.option("--output", "-o", default="",
help="Path to where output file will be placed. Default: empty")
@click.option("proxyhost", "--proxy-host", "-ph", multiple=False, type=str, default=None,
help="Proxy host IP or DNS --proxy-host")
@click.option("proxyport", "--proxy-port", "-pp", multiple=False, type=int, default=80,
help="Proxy port number --proxy-port")
@click.option("proxyprotocol", "--proxy-protocol", "-pr", multiple=False, type=str, default='http',
help="Proxy protocol (https or http) --proxy-protocol")
def check(key, db, json, full_report, bare, stdin, files, cache, ignore, output, proxyprotocol, proxyhost, proxyport):
if files and stdin:
click.secho("Can't read from --stdin and --file at the same time, exiting", fg="red")
click.secho("Can't read from --stdin and --file at the same time, exiting", fg="red", file=sys.stderr)
sys.exit(-1)
if files:
@@ -57,33 +60,72 @@ def check(key, db, json, full_report, bare, stdin, files, cache, ignore):
elif stdin:
packages = list(read_requirements(sys.stdin))
else:
packages = get_installed_distributions()
import pkg_resources
packages = [
d for d in pkg_resources.working_set
if d.key not in {"python", "wsgiref", "argparse"}
]
proxy_dictionary = {}
if proxyhost is not None:
if proxyprotocol in ["http", "https"]:
proxy_dictionary = {proxyprotocol: "{0}://{1}:{2}".format(proxyprotocol, proxyhost, str(proxyport))}
else:
click.secho("Proxy Protocol should be http or https only.", fg="red")
sys.exit(-1)
try:
vulns = safety.check(packages=packages, key=key, db_mirror=db, cached=cache, ignore_ids=ignore)
click.secho(report(
vulns=vulns,
full=full_report,
json_report=json,
bare_report=bare,
checked_packages=len(packages),
db=db,
key=key
)
)
vulns = safety.check(packages=packages, key=key, db_mirror=db, cached=cache, ignore_ids=ignore, proxy=proxy_dictionary)
output_report = report(vulns=vulns,
full=full_report,
json_report=json,
bare_report=bare,
checked_packages=len(packages),
db=db,
key=key)
if output:
with open(output, 'w+') as output_file:
output_file.write(output_report)
else:
click.secho(output_report, nl=False if bare and not vulns else True)
sys.exit(-1 if vulns else 0)
except InvalidKeyError:
click.secho("Your API Key '{key}' is invalid. See {link}".format(
key=key, link='https://goo.gl/O7Y1rS'),
fg="red")
fg="red",
file=sys.stderr)
sys.exit(-1)
except DatabaseFileNotFoundError:
click.secho("Unable to load vulnerability database from {db}".format(db=db), fg="red")
click.secho("Unable to load vulnerability database from {db}".format(db=db), fg="red", file=sys.stderr)
sys.exit(-1)
except DatabaseFetchError:
click.secho("Unable to load vulnerability database", fg="red")
click.secho("Unable to load vulnerability database", fg="red", file=sys.stderr)
sys.exit(-1)
@cli.command()
@click.option("--full-report/--short-report", default=False,
help='Full reports include a security advisory (if available). Default: '
'--short-report')
@click.option("--bare/--not-bare", default=False,
help='Output vulnerable packages only. Useful in combination with other tools.'
'Default: --not-bare')
@click.option("file", "--file", "-f", type=click.File(), required=True,
help="Read input from an insecure report file. Default: empty")
def review(full_report, bare, file):
if full_report and bare:
click.secho("Can't choose both --bare and --full-report/--short-report", fg="red")
sys.exit(-1)
try:
input_vulns = read_vulnerabilities(file)
except JSONDecodeError:
click.secho("Not a valid JSON file", fg="red")
sys.exit(-1)
vulns = safety.review(input_vulns)
output_report = report(vulns=vulns, full=full_report, bare_report=bare)
click.secho(output_report, nl=False if bare and not vulns else True)
if __name__ == "__main__":
cli()
+5 -3
View File
@@ -3,6 +3,7 @@ import platform
import sys
import json
import os
import textwrap
# python 2.7 compat
try:
@@ -110,9 +111,10 @@ class SheetReport(object):
descr = get_advisory(vuln)
for chunk in [descr[i:i + 76] for i in range(0, len(descr), 76)]:
for line in chunk.splitlines():
for pn, paragraph in enumerate(descr.replace('\r', '').split('\n\n')):
if pn:
table.append("{:76}".format(''))
for line in textwrap.wrap(paragraph, width=76):
try:
table.append("{:76}".format(line.encode('utf-8')))
except TypeError:
+23 -8
View File
@@ -9,6 +9,7 @@ import json
import time
import errno
class Vulnerability(namedtuple("Vulnerability",
["name", "spec", "version", "advisory", "vuln_id"])):
pass
@@ -64,7 +65,7 @@ def write_to_cache(db_name, data):
f.write(json.dumps(cache))
def fetch_database_url(mirror, db_name, key, cached):
def fetch_database_url(mirror, db_name, key, cached, proxy):
headers = {}
if key:
@@ -74,9 +75,8 @@ def fetch_database_url(mirror, db_name, key, cached):
cached_data = get_from_cache(db_name=db_name)
if cached_data:
return cached_data
url = mirror + db_name
r = requests.get(url=url, timeout=REQUEST_TIMEOUT, headers=headers)
r = requests.get(url=url, timeout=REQUEST_TIMEOUT, headers=headers, proxies=proxy)
if r.status_code == 200:
data = r.json()
if cached:
@@ -94,7 +94,7 @@ def fetch_database_file(path, db_name):
return json.loads(f.read())
def fetch_database(full=False, key=False, db=False, cached=False):
def fetch_database(full=False, key=False, db=False, cached=False, proxy={}):
if db:
mirrors = [db]
@@ -105,7 +105,7 @@ def fetch_database(full=False, key=False, db=False, cached=False):
for mirror in mirrors:
# mirror can either be a local path or a URL
if mirror.startswith("http://") or mirror.startswith("https://"):
data = fetch_database_url(mirror, db_name=db_name, key=key, cached=cached)
data = fetch_database_url(mirror, db_name=db_name, key=key, cached=cached, proxy=proxy)
else:
data = fetch_database_file(mirror, db_name=db_name)
if data:
@@ -120,10 +120,9 @@ def get_vulnerabilities(pkg, spec, db):
yield entry
def check(packages, key, db_mirror, cached, ignore_ids):
def check(packages, key, db_mirror, cached, ignore_ids, proxy):
key = key if key else os.environ.get("SAFETY_API_KEY", False)
db = fetch_database(key=key, db=db_mirror, cached=cached)
db = fetch_database(key=key, db=db_mirror, cached=cached, proxy=proxy)
db_full = None
vulnerable_packages = frozenset(db.keys())
vulnerable = []
@@ -152,3 +151,19 @@ def check(packages, key, db_mirror, cached, ignore_ids):
)
)
return vulnerable
def review(vulnerabilities):
vulnerable = []
for vuln in vulnerabilities:
current_vuln = {
"name": vuln[0],
"spec": vuln[1],
"version": vuln[2],
"advisory": vuln[3],
"vuln_id": vuln[4],
}
vulnerable.append(
Vulnerability(**current_vuln)
)
return vulnerable
+8 -1
View File
@@ -1,11 +1,17 @@
from dparse.parser import setuptools_parse_requirements_backport as _parse_requirements
from collections import namedtuple
import click
import sys
import json
import os
Package = namedtuple("Package", ["key", "version"])
RequirementFile = namedtuple("RequirementFile", ["path"])
def read_vulnerabilities(fh):
return json.load(fh)
def iter_lines(fh, lineno=0):
for line in fh.readlines()[lineno:]:
yield line
@@ -85,7 +91,8 @@ def read_requirements(fh, resolve=False):
"Warning: unpinned requirement '{req}' found in {fname}, "
"unable to check.".format(req=req.name,
fname=fname),
fg="yellow"
fg="yellow",
file=sys.stderr
)
except ValueError:
continue
+2 -2
View File
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
import sys
import json
import os
import platform
import json
import sys
def format_full_version(info):
+15 -17
View File
@@ -12,31 +12,29 @@ from __future__ import absolute_import
import os
import sys
import time
import crayons
from .environments import PIPENV_COLORBLIND, PIPENV_HIDE_EMOJIS
STREAM = sys.stderr
MILL_TEMPLATE = "%s %s %i/%i\r"
DOTS_CHAR = "."
if os.name != "nt":
if PIPENV_HIDE_EMOJIS:
if PIPENV_COLORBLIND:
BAR_FILLED_CHAR = "="
BAR_EMPTY_CHAR = "-"
else:
BAR_FILLED_CHAR = str(crayons.green("=", bold=True))
BAR_EMPTY_CHAR = str(crayons.black("-"))
if PIPENV_HIDE_EMOJIS:
if PIPENV_COLORBLIND:
BAR_FILLED_CHAR = "="
BAR_EMPTY_CHAR = "-"
else:
if PIPENV_COLORBLIND:
BAR_FILLED_CHAR = ""
BAR_EMPTY_CHAR = " "
else:
BAR_FILLED_CHAR = str(crayons.green("", bold=True))
BAR_EMPTY_CHAR = str(crayons.black(""))
BAR_FILLED_CHAR = str(crayons.green("=", bold=True))
BAR_EMPTY_CHAR = str(crayons.black("-"))
else:
BAR_FILLED_CHAR = "="
BAR_EMPTY_CHAR = "-"
if PIPENV_COLORBLIND:
BAR_FILLED_CHAR = ""
BAR_EMPTY_CHAR = " "
else:
BAR_FILLED_CHAR = str(crayons.green("", bold=True))
BAR_EMPTY_CHAR = str(crayons.black(""))
if (sys.version_info[0] >= 3) and (os.name != "nt"):
BAR_TEMPLATE = u" %s%s%s %i/%i{0}\r".format(crayons.black("%s"))
+87 -81
View File
@@ -1,54 +1,42 @@
# -*- coding: utf-8 -*-
import base64
import fnmatch
import glob
import hashlib
import io
import json
import operator
import os
import re
import sys
import glob
import base64
import fnmatch
import hashlib
from first import first
from cached_property import cached_property
import operator
import pipfile
import pipfile.api
import six
import vistir
import toml
import tomlkit
import vistir
from first import first
import pipfile
import pipfile.api
from .vendor.cached_property import cached_property
from .environment import Environment
from .cmdparse import Script
from .utils import (
pep423_name,
proper_case,
find_requirements,
is_editable,
cleanup_toml,
convert_toml_outline_tables,
is_installable_file,
is_valid_url,
get_url_name,
normalize_drive,
python_version,
safe_expandvars,
is_star,
get_workon_home,
is_virtual_environment,
looks_like_dir,
get_canonical_names
)
from .environment import Environment
from .environments import (
PIPENV_MAX_DEPTH,
PIPENV_PIPFILE,
PIPENV_VENV_IN_PROJECT,
PIPENV_TEST_INDEX,
PIPENV_PYTHON,
PIPENV_DEFAULT_PYTHON_VERSION,
PIPENV_IGNORE_VIRTUALENVS,
PIPENV_DEFAULT_PYTHON_VERSION, PIPENV_IGNORE_VIRTUALENVS, PIPENV_MAX_DEPTH,
PIPENV_PIPFILE, PIPENV_PYTHON, PIPENV_TEST_INDEX, PIPENV_VENV_IN_PROJECT,
is_in_virtualenv
)
from .vendor.requirementslib.models.utils import get_default_pyproject_backend
from .utils import (
cleanup_toml, convert_toml_outline_tables, find_requirements,
get_canonical_names, get_url_name, get_workon_home, is_editable,
is_installable_file, is_star, is_valid_url, is_virtual_environment,
looks_like_dir, normalize_drive, pep423_name, proper_case, python_version,
safe_expandvars, get_pipenv_dist
)
def _normalized(p):
@@ -111,6 +99,9 @@ if PIPENV_PIPFILE:
else:
PIPENV_PIPFILE = _normalized(PIPENV_PIPFILE)
# Overwrite environment variable so that subprocesses can get the correct path.
# See https://github.com/pypa/pipenv/issues/3584
os.environ['PIPENV_PIPFILE'] = PIPENV_PIPFILE
# (path, file contents) => TOMLFile
# keeps track of pipfiles that we've seen so we do not need to re-parse 'em
_pipfile_cache = {}
@@ -353,7 +344,11 @@ class Project(object):
prefix=prefix, is_venv=is_venv, sources=sources, pipfile=self.parsed_pipfile,
project=self
)
self._environment.add_dist("pipenv")
pipenv_dist = get_pipenv_dist(pkg="pipenv")
if pipenv_dist:
self._environment.extend_dists(pipenv_dist)
else:
self._environment.add_dist("pipenv")
return self._environment
def get_outdated_packages(self):
@@ -538,18 +533,19 @@ class Project(object):
if not os.path.exists(self.path_to("setup.py")):
if not build_system or not build_system.get("requires"):
build_system = {
"requires": ["setuptools>=38.2.5", "wheel"],
"build-backend": "setuptools.build_meta",
"requires": ["setuptools>=40.8.0", "wheel"],
"build-backend": get_default_pyproject_backend(),
}
self._build_system = build_system
@property
def build_requires(self):
return self._build_system.get("requires", [])
return self._build_system.get("requires", ["setuptools>=40.8.0", "wheel"])
@property
def build_backend(self):
return self._build_system.get("build-backend", None)
return self._build_system.get("build-backend", get_default_pyproject_backend())
@property
def settings(self):
@@ -616,10 +612,8 @@ class Project(object):
def _get_editable_packages(self, dev=False):
section = "dev-packages" if dev else "packages"
# section = "{0}-editable".format(section)
packages = {
k: v
# for k, v in self._pipfile[section].items()
for k, v in self.parsed_pipfile.get(section, {}).items()
if is_editable(k) or is_editable(v)
}
@@ -628,10 +622,8 @@ class Project(object):
def _get_vcs_packages(self, dev=False):
from pipenv.vendor.requirementslib.utils import is_vcs
section = "dev-packages" if dev else "packages"
# section = "{0}-vcs".format(section)
packages = {
k: v
# for k, v in self._pipfile[section].items()
for k, v in self.parsed_pipfile.get(section, {}).items()
if is_vcs(v) or is_vcs(k)
}
@@ -693,7 +685,8 @@ class Project(object):
ConfigOptionParser, make_option_group, index_group
)
config_parser = ConfigOptionParser(name=self.name)
name = self.name if self.name is not None else "Pipfile"
config_parser = ConfigOptionParser(name=name)
config_parser.add_option_group(make_option_group(index_group, config_parser))
install = config_parser.option_groups[0]
indexes = (
@@ -742,10 +735,19 @@ class Project(object):
source["verify_ssl"] = source["verify_ssl"].lower() == "true"
return source
def get_or_create_lockfile(self):
def get_or_create_lockfile(self, from_pipfile=False):
from pipenv.vendor.requirementslib.models.lockfile import Lockfile as Req_Lockfile
lockfile = None
if self.lockfile_exists:
if from_pipfile and self.pipfile_exists:
lockfile_dict = {
"default": self._lockfile["default"].copy(),
"develop": self._lockfile["develop"].copy()
}
lockfile_dict.update({"_meta": self.get_lockfile_meta()})
lockfile = Req_Lockfile.from_data(
path=self.lockfile_location, data=lockfile_dict, meta_from_project=False
)
elif self.lockfile_exists:
try:
lockfile = Req_Lockfile.load(self.lockfile_location)
except OSError:
@@ -769,29 +771,21 @@ class Project(object):
)
lockfile._lockfile = lockfile.projectfile.model = _created_lockfile
return lockfile
elif self.pipfile_exists:
lockfile_dict = {
"default": self._lockfile["default"].copy(),
"develop": self._lockfile["develop"].copy()
}
lockfile_dict.update({"_meta": self.get_lockfile_meta()})
_created_lockfile = Req_Lockfile.from_data(
path=self.lockfile_location, data=lockfile_dict, meta_from_project=False
)
lockfile._lockfile = _created_lockfile
return lockfile
else:
return self.get_or_create_lockfile(from_pipfile=True)
def get_lockfile_meta(self):
from .vendor.plette.lockfiles import PIPFILE_SPEC_CURRENT
sources = self.lockfile_content.get("_meta", {}).get("sources", [])
if not sources:
sources = self.pipfile_sources
elif not isinstance(sources, list):
if self.lockfile_exists:
sources = self.lockfile_content.get("_meta", {}).get("sources", [])
else:
sources = [dict(source) for source in self.parsed_pipfile["source"]]
if not isinstance(sources, list):
sources = [sources,]
return {
"hash": {"sha256": self.calculate_pipfile_hash()},
"pipfile-spec": PIPFILE_SPEC_CURRENT,
"sources": sources,
"sources": [self.populate_source(s) for s in sources],
"requires": self.parsed_pipfile.get("requires", {})
}
@@ -867,7 +861,8 @@ class Project(object):
return self.pipfile_sources
def find_source(self, source):
"""given a source, find it.
"""
Given a source, find it.
source can be a url or an index name.
"""
@@ -880,23 +875,34 @@ class Project(object):
source = self.get_source(url=source)
return source
def get_source(self, name=None, url=None):
def get_source(self, name=None, url=None, refresh=False):
from .utils import is_url_equal
def find_source(sources, name=None, url=None):
source = None
if name:
source = [s for s in sources if s.get("name") == name]
source = next(iter(
s for s in sources if "name" in s and s["name"] == name
), None)
elif url:
source = [s for s in sources if url.startswith(s.get("url"))]
if source:
return first(source)
source = next(iter(
s for s in sources
if "url" in s and is_url_equal(url, s.get("url", ""))
), None)
if source is not None:
return source
found_source = find_source(self.sources, name=name, url=url)
if found_source:
return found_source
found_source = find_source(self.pipfile_sources, name=name, url=url)
if found_source:
return found_source
raise SourceNotFound(name or url)
sources = (self.sources, self.pipfile_sources)
if refresh:
self.clear_pipfile_cache()
sources = reversed(sources)
found = next(
iter(find_source(source, name=name, url=url) for source in sources), None
)
target = next(iter(t for t in (name, url) if t is not None))
if found is None:
raise SourceNotFound(target)
return found
def get_package_name_in_pipfile(self, package_name, dev=False):
"""Get the equivalent package name in pipfile"""
@@ -941,17 +947,17 @@ class Project(object):
# Don't re-capitalize file URLs or VCSs.
if not isinstance(package, Requirement):
package = Requirement.from_line(package.strip())
_, converted = package.pipfile_entry
req_name, converted = package.pipfile_entry
key = "dev-packages" if dev else "packages"
# Set empty group if it doesn't exist yet.
if key not in p:
p[key] = {}
name = self.get_package_name_in_pipfile(package.name, dev)
name = self.get_package_name_in_pipfile(req_name, dev)
if name and is_star(converted):
# Skip for wildcard version
return
# Add the package to the group.
p[key][name or package.normalized_name] = converted
p[key][name or pep423_name(req_name)] = converted
# Write Pipfile.
self.write_toml(p)
+1 -2
View File
@@ -1,9 +1,8 @@
import operator
import re
from .vendor import attr, delegator
from .environments import PIPENV_INSTALL_TIMEOUT
from .vendor import attr, delegator
@attr.s
+117 -43
View File
@@ -1,17 +1,54 @@
import os
import sys
import json
import logging
import os
import sys
os.environ["PIP_PYTHON_PATH"] = str(sys.executable)
def _patch_path():
def find_site_path(pkg, site_dir=None):
import pkg_resources
if site_dir is not None:
site_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
working_set = pkg_resources.WorkingSet([site_dir] + sys.path[:])
for dist in working_set:
root = dist.location
base_name = dist.project_name if dist.project_name else dist.key
name = None
if "top_level.txt" in dist.metadata_listdir(""):
name = next(iter([l.strip() for l in dist.get_metadata_lines("top_level.txt") if l is not None]), None)
if name is None:
name = pkg_resources.safe_name(base_name).replace("-", "_")
if not any(pkg == _ for _ in [base_name, name]):
continue
path_options = [name, "{0}.py".format(name)]
path_options = [os.path.join(root, p) for p in path_options if p is not None]
path = next(iter(p for p in path_options if os.path.exists(p)), None)
if path is not None:
return (dist, path)
return (None, None)
def _patch_path(pipenv_site=None):
import site
pipenv_libdir = os.path.dirname(os.path.abspath(__file__))
pipenv_site_dir = os.path.dirname(pipenv_libdir)
site.addsitedir(pipenv_site_dir)
for _dir in ("vendor", "patched"):
pipenv_dist = None
if pipenv_site is not None:
pipenv_dist, pipenv_path = find_site_path("pipenv", site_dir=pipenv_site)
else:
pipenv_dist, pipenv_path = find_site_path("pipenv", site_dir=pipenv_site_dir)
if pipenv_dist is not None:
pipenv_dist.activate()
else:
site.addsitedir(next(iter(
sitedir for sitedir in (pipenv_site, pipenv_site_dir)
if sitedir is not None
), None))
if pipenv_path is not None:
pipenv_libdir = pipenv_path
for _dir in ("vendor", "patched", pipenv_libdir):
sys.path.insert(0, os.path.join(pipenv_libdir, _dir))
@@ -23,8 +60,11 @@ def get_parser():
parser.add_argument("--verbose", "-v", action="count", default=False)
parser.add_argument("--debug", action="store_true", default=False)
parser.add_argument("--system", action="store_true", default=False)
parser.add_argument("--parse-only", action="store_true", default=False)
parser.add_argument("--pipenv-site", metavar="pipenv_site_dir", action="store",
default=os.environ.get("PIPENV_SITE_DIR"))
parser.add_argument("--requirements-dir", metavar="requirements_dir", action="store",
default=os.environ.get("PIPENV_REQ_DIR"))
default=os.environ.get("PIPENV_REQ_DIR"))
parser.add_argument("packages", nargs="*")
return parser
@@ -40,22 +80,53 @@ def handle_parsed_args(parsed):
logging.getLogger("notpip").setLevel(logging.DEBUG)
elif parsed.verbose > 0:
logging.getLogger("notpip").setLevel(logging.INFO)
os.environ["PIPENV_VERBOSITY"] = str(parsed.verbose)
if "PIPENV_PACKAGES" in os.environ:
parsed.packages += os.environ.get("PIPENV_PACKAGES", "").strip().split("\n")
return parsed
def _main(pre, clear, verbose, system, requirements_dir, packages):
os.environ["PIP_PYTHON_VERSION"] = ".".join([str(s) for s in sys.version_info[:3]])
os.environ["PIP_PYTHON_PATH"] = str(sys.executable)
def parse_packages(packages, pre, clear, system, requirements_dir=None):
from pipenv.vendor.requirementslib.models.requirements import Requirement
from pipenv.vendor.vistir.contextmanagers import cd, temp_path
from pipenv.utils import parse_indexes
parsed_packages = []
for package in packages:
indexes, trusted_hosts, line = parse_indexes(package)
line = " ".join(line)
pf = dict()
req = Requirement.from_line(line)
if not req.name:
with temp_path(), cd(req.req.setup_info.base_dir):
sys.path.insert(0, req.req.setup_info.base_dir)
req.req._setup_info.get_info()
req.update_name_from_path(req.req.setup_info.base_dir)
print(os.listdir(req.req.setup_info.base_dir))
try:
name, entry = req.pipfile_entry
except Exception:
continue
else:
if name is not None and entry is not None:
pf[name] = entry
parsed_packages.append(pf)
print("RESULTS:")
if parsed_packages:
print(json.dumps(parsed_packages))
else:
print(json.dumps([]))
def resolve_packages(pre, clear, verbose, system, requirements_dir, packages):
from pipenv.utils import create_mirror_source, resolve_deps, replace_pypi_sources
pypi_mirror_source = (
create_mirror_source(os.environ["PIPENV_PYPI_MIRROR"])
if "PIPENV_PYPI_MIRROR" in os.environ
else None
)
# os.environ["PIP_NO_BUILD_ISOLATION"] = "1"
# os.environ["PIP_NO_USE_PEP517"] = "1"
# os.environ["PIP_NO_DEPS"] = "1"
def resolve(packages, pre, project, sources, clear, system, requirements_dir=None):
return resolve_deps(
@@ -75,15 +146,8 @@ def _main(pre, clear, verbose, system, requirements_dir, packages):
if pypi_mirror_source
else project.pipfile_sources
)
results = resolve(
packages,
pre=pre,
project=project,
sources=sources,
clear=clear,
system=system,
requirements_dir=requirements_dir,
)
results = resolve(packages, pre=pre, project=project, sources=sources, clear=clear,
system=system, requirements_dir=requirements_dir)
print("RESULTS:")
if results:
print(json.dumps(results))
@@ -91,36 +155,46 @@ def _main(pre, clear, verbose, system, requirements_dir, packages):
print(json.dumps([]))
def main():
_patch_path()
import warnings
from pipenv.vendor.vistir.compat import ResourceWarning
warnings.simplefilter("ignore", category=ResourceWarning)
import io
import six
if six.PY3:
import atexit
stdout_wrapper = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8')
atexit.register(stdout_wrapper.close)
stderr_wrapper = io.TextIOWrapper(sys.stderr.buffer, encoding='utf8')
atexit.register(stderr_wrapper.close)
sys.stdout = stdout_wrapper
sys.stderr = stderr_wrapper
def _main(pre, clear, verbose, system, requirements_dir, packages, parse_only=False):
os.environ["PIP_PYTHON_VERSION"] = ".".join([str(s) for s in sys.version_info[:3]])
os.environ["PIP_PYTHON_PATH"] = str(sys.executable)
if parse_only:
parse_packages(
packages,
pre=pre,
clear=clear,
system=system,
requirements_dir=requirements_dir,
)
else:
from pipenv._compat import force_encoding
force_encoding()
os.environ["PIP_DISABLE_PIP_VERSION_CHECK"] = str("1")
os.environ["PYTHONIOENCODING"] = str("utf-8")
resolve_packages(pre, clear, verbose, system, requirements_dir, packages)
def main():
parser = get_parser()
parsed, remaining = parser.parse_known_args()
# sys.argv = remaining
_patch_path(pipenv_site=parsed.pipenv_site)
import warnings
from pipenv.vendor.vistir.compat import ResourceWarning
from pipenv.vendor.vistir.misc import get_wrapped_stream
warnings.simplefilter("ignore", category=ResourceWarning)
import six
if six.PY3:
stdout = sys.stdout.buffer
stderr = sys.stderr.buffer
else:
stdout = sys.stdout
stderr = sys.stderr
sys.stderr = get_wrapped_stream(stderr)
sys.stdout = get_wrapped_stream(stdout)
from pipenv.vendor import colorama
colorama.init()
os.environ["PIP_DISABLE_PIP_VERSION_CHECK"] = str("1")
os.environ["PYTHONIOENCODING"] = str("utf-8")
parsed = handle_parsed_args(parsed)
_main(parsed.pre, parsed.clear, parsed.verbose, parsed.system,
parsed.requirements_dir, parsed.packages)
parsed.requirements_dir, parsed.packages, parse_only=parsed.parse_only)
if __name__ == "__main__":
_patch_path()
from pipenv.vendor import colorama
colorama.init()
main()
+3 -3
View File
@@ -5,10 +5,10 @@ import signal
import subprocess
import sys
from .environments import PIPENV_SHELL_EXPLICIT, PIPENV_SHELL, PIPENV_EMULATOR
from .vendor.vistir.compat import get_terminal_size, Path
from .vendor.vistir.contextmanagers import temp_environ
from .environments import PIPENV_EMULATOR, PIPENV_SHELL, PIPENV_SHELL_EXPLICIT
from .vendor import shellingham
from .vendor.vistir.compat import Path, get_terminal_size
from .vendor.vistir.contextmanagers import temp_environ
ShellDetectionFailure = shellingham.ShellDetectionFailure
+638 -258
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -18,7 +18,7 @@ from ._make import (
)
__version__ = "18.2.0"
__version__ = "19.1.0"
__title__ = "attrs"
__description__ = "Classes Without Boilerplate"
+15 -12
View File
@@ -23,9 +23,9 @@ from . import validators as validators
_T = TypeVar("_T")
_C = TypeVar("_C", bound=type)
_ValidatorType = Callable[[Any, Attribute, _T], Any]
_ValidatorType = Callable[[Any, Attribute[_T], _T], Any]
_ConverterType = Callable[[Any], _T]
_FilterType = Callable[[Attribute, Any], bool]
_FilterType = Callable[[Attribute[_T], _T], bool]
# FIXME: in reality, if multiple validators are passed they must be in a list or tuple,
# but those are invariant and so would prevent subtypes of _ValidatorType from working
# when passed in a list or tuple.
@@ -57,10 +57,10 @@ class Attribute(Generic[_T]):
metadata: Dict[Any, Any]
type: Optional[Type[_T]]
kw_only: bool
def __lt__(self, x: Attribute) -> bool: ...
def __le__(self, x: Attribute) -> bool: ...
def __gt__(self, x: Attribute) -> bool: ...
def __ge__(self, x: Attribute) -> bool: ...
def __lt__(self, x: Attribute[_T]) -> bool: ...
def __le__(self, x: Attribute[_T]) -> bool: ...
def __gt__(self, x: Attribute[_T]) -> bool: ...
def __ge__(self, x: Attribute[_T]) -> bool: ...
# NOTE: We had several choices for the annotation to use for type arg:
# 1) Type[_T]
@@ -167,6 +167,7 @@ def attrs(
auto_attribs: bool = ...,
kw_only: bool = ...,
cache_hash: bool = ...,
auto_exc: bool = ...,
) -> _C: ...
@overload
def attrs(
@@ -184,14 +185,15 @@ def attrs(
auto_attribs: bool = ...,
kw_only: bool = ...,
cache_hash: bool = ...,
auto_exc: bool = ...,
) -> Callable[[_C], _C]: ...
# TODO: add support for returning NamedTuple from the mypy plugin
class _Fields(Tuple[Attribute, ...]):
def __getattr__(self, name: str) -> Attribute: ...
class _Fields(Tuple[Attribute[Any], ...]):
def __getattr__(self, name: str) -> Attribute[Any]: ...
def fields(cls: type) -> _Fields: ...
def fields_dict(cls: type) -> Dict[str, Attribute]: ...
def fields_dict(cls: type) -> Dict[str, Attribute[Any]]: ...
def validate(inst: Any) -> None: ...
# TODO: add support for returning a proper attrs class from the mypy plugin
@@ -212,6 +214,7 @@ def make_class(
auto_attribs: bool = ...,
kw_only: bool = ...,
cache_hash: bool = ...,
auto_exc: bool = ...,
) -> type: ...
# _funcs --
@@ -223,7 +226,7 @@ def make_class(
def asdict(
inst: Any,
recurse: bool = ...,
filter: Optional[_FilterType] = ...,
filter: Optional[_FilterType[Any]] = ...,
dict_factory: Type[Mapping[Any, Any]] = ...,
retain_collection_types: bool = ...,
) -> Dict[str, Any]: ...
@@ -232,8 +235,8 @@ def asdict(
def astuple(
inst: Any,
recurse: bool = ...,
filter: Optional[_FilterType] = ...,
tuple_factory: Type[Sequence] = ...,
filter: Optional[_FilterType[Any]] = ...,
tuple_factory: Type[Sequence[Any]] = ...,
retain_collection_types: bool = ...,
) -> Tuple[Any, ...]: ...
def has(cls: type) -> bool: ...
+21 -25
View File
@@ -20,6 +20,7 @@ else:
if PY2:
from UserDict import IterableUserDict
from collections import Mapping, Sequence # noqa
# We 'bundle' isclass instead of using inspect as importing inspect is
# fairly expensive (order of 10-15 ms for a modern machine in 2016)
@@ -89,8 +90,27 @@ if PY2:
res.data.update(d) # We blocked update, so we have to do it like this.
return res
def just_warn(*args, **kw): # pragma: nocover
"""
We only warn on Python 3 because we are not aware of any concrete
consequences of not setting the cell on Python 2.
"""
else:
else: # Python 3 and later.
from collections.abc import Mapping, Sequence # noqa
def just_warn(*args, **kw):
"""
We only warn on Python 3 because we are not aware of any concrete
consequences of not setting the cell on Python 2.
"""
warnings.warn(
"Missing ctypes. Some features like bare super() or accessing "
"__class__ will not work with slotted classes.",
RuntimeWarning,
stacklevel=2,
)
def isclass(klass):
return isinstance(klass, type)
@@ -113,30 +133,6 @@ def import_ctypes():
return ctypes
if not PY2:
def just_warn(*args, **kw):
"""
We only warn on Python 3 because we are not aware of any concrete
consequences of not setting the cell on Python 2.
"""
warnings.warn(
"Missing ctypes. Some features like bare super() or accessing "
"__class__ will not work with slots classes.",
RuntimeWarning,
stacklevel=2,
)
else:
def just_warn(*args, **kw): # pragma: nocover
"""
We only warn on Python 3 because we are not aware of any concrete
consequences of not setting the cell on Python 2.
"""
def make_set_closure_cell():
"""
Moved into a function for testability.
+79 -27
View File
@@ -409,12 +409,11 @@ def _transform_attrs(cls, these, auto_attribs, kw_only):
a.kw_only is False
):
had_default = True
if was_kw_only is True and a.kw_only is False:
if was_kw_only is True and a.kw_only is False and a.init is True:
raise ValueError(
"Non keyword-only attributes are not allowed after a "
"keyword-only attribute. Attribute in question: {a!r}".format(
a=a
)
"keyword-only attribute (unless they are init=False). "
"Attribute in question: {a!r}".format(a=a)
)
if was_kw_only is False and a.init is True and a.kw_only is True:
was_kw_only = True
@@ -454,6 +453,7 @@ class _ClassBuilder(object):
"_has_post_init",
"_delete_attribs",
"_base_attr_map",
"_is_exc",
)
def __init__(
@@ -466,6 +466,7 @@ class _ClassBuilder(object):
auto_attribs,
kw_only,
cache_hash,
is_exc,
):
attrs, base_attrs, base_map = _transform_attrs(
cls, these, auto_attribs, kw_only
@@ -483,6 +484,7 @@ class _ClassBuilder(object):
self._cache_hash = cache_hash
self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False))
self._delete_attribs = not bool(these)
self._is_exc = is_exc
self._cls_dict["__attrs_attrs__"] = self._attrs
@@ -530,6 +532,26 @@ class _ClassBuilder(object):
for name, value in self._cls_dict.items():
setattr(cls, name, value)
# Attach __setstate__. This is necessary to clear the hash code
# cache on deserialization. See issue
# https://github.com/python-attrs/attrs/issues/482 .
# Note that this code only handles setstate for dict classes.
# For slotted classes, see similar code in _create_slots_class .
if self._cache_hash:
existing_set_state_method = getattr(cls, "__setstate__", None)
if existing_set_state_method:
raise NotImplementedError(
"Currently you cannot use hash caching if "
"you specify your own __setstate__ method."
"See https://github.com/python-attrs/attrs/issues/494 ."
)
def cache_hash_set_state(chss_self, _):
# clear hash code cache
setattr(chss_self, _hash_cache_field, None)
setattr(cls, "__setstate__", cache_hash_set_state)
return cls
def _create_slots_class(self):
@@ -582,6 +604,8 @@ class _ClassBuilder(object):
"""
return tuple(getattr(self, name) for name in state_attr_names)
hash_caching_enabled = self._cache_hash
def slots_setstate(self, state):
"""
Automatically created by attrs.
@@ -589,6 +613,13 @@ class _ClassBuilder(object):
__bound_setattr = _obj_setattr.__get__(self, Attribute)
for name, value in zip(state_attr_names, state):
__bound_setattr(name, value)
# Clearing the hash code cache on deserialization is needed
# because hash codes can change from run to run. See issue
# https://github.com/python-attrs/attrs/issues/482 .
# Note that this code only handles setstate for slotted classes.
# For dict classes, see similar code in _patch_original_class .
if hash_caching_enabled:
__bound_setattr(_hash_cache_field, None)
# slots and frozen require __getstate__/__setstate__ to work
cd["__getstate__"] = slots_getstate
@@ -660,6 +691,7 @@ class _ClassBuilder(object):
self._slots,
self._cache_hash,
self._base_attr_map,
self._is_exc,
)
)
@@ -710,6 +742,7 @@ def attrs(
auto_attribs=False,
kw_only=False,
cache_hash=False,
auto_exc=False,
):
r"""
A class decorator that adds `dunder
@@ -815,10 +848,23 @@ def attrs(
:param bool cache_hash: Ensure that the object's hash code is computed
only once and stored on the object. If this is set to ``True``,
hashing must be either explicitly or implicitly enabled for this
class. If the hash code is cached, then no attributes of this
class which participate in hash code computation may be mutated
after object creation.
class. If the hash code is cached, avoid any reassignments of
fields involved in hash code computation or mutations of the objects
those fields point to after object creation. If such changes occur,
the behavior of the object's hash code is undefined.
:param bool auto_exc: If the class subclasses :class:`BaseException`
(which implicitly includes any subclass of any exception), the
following happens to behave like a well-behaved Python exceptions
class:
- the values for *cmp* and *hash* are ignored and the instances compare
and hash by the instance's ids (N.B. ``attrs`` will *not* remove
existing implementations of ``__hash__`` or the equality methods. It
just won't add own ones.),
- all attributes that are either passed into ``__init__`` or have a
default value are additionally available as a tuple in the ``args``
attribute,
- the value of *str* is ignored leaving ``__str__`` to base classes.
.. versionadded:: 16.0.0 *slots*
.. versionadded:: 16.1.0 *frozen*
@@ -838,12 +884,16 @@ def attrs(
to each other.
.. versionadded:: 18.2.0 *kw_only*
.. versionadded:: 18.2.0 *cache_hash*
.. versionadded:: 19.1.0 *auto_exc*
"""
def wrap(cls):
if getattr(cls, "__class__", None) is None:
raise TypeError("attrs only works with new-style classes.")
is_exc = auto_exc is True and issubclass(cls, BaseException)
builder = _ClassBuilder(
cls,
these,
@@ -853,13 +903,14 @@ def attrs(
auto_attribs,
kw_only,
cache_hash,
is_exc,
)
if repr is True:
builder.add_repr(repr_ns)
if str is True:
builder.add_str()
if cmp is True:
if cmp is True and not is_exc:
builder.add_cmp()
if hash is not True and hash is not False and hash is not None:
@@ -874,7 +925,11 @@ def attrs(
" hashing must be either explicitly or implicitly "
"enabled."
)
elif hash is True or (hash is None and cmp is True and frozen is True):
elif (
hash is True
or (hash is None and cmp is True and frozen is True)
and is_exc is False
):
builder.add_hash()
else:
if cache_hash:
@@ -1213,7 +1268,9 @@ def _add_repr(cls, ns=None, attrs=None):
return cls
def _make_init(attrs, post_init, frozen, slots, cache_hash, base_attr_map):
def _make_init(
attrs, post_init, frozen, slots, cache_hash, base_attr_map, is_exc
):
attrs = [a for a in attrs if a.init or a.default is not NOTHING]
# We cache the generated init methods for the same kinds of attributes.
@@ -1222,16 +1279,18 @@ def _make_init(attrs, post_init, frozen, slots, cache_hash, base_attr_map):
unique_filename = "<attrs generated init {0}>".format(sha1.hexdigest())
script, globs, annotations = _attrs_to_init_script(
attrs, frozen, slots, post_init, cache_hash, base_attr_map
attrs, frozen, slots, post_init, cache_hash, base_attr_map, is_exc
)
locs = {}
bytecode = compile(script, unique_filename, "exec")
attr_dict = dict((a.name, a) for a in attrs)
globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict})
if frozen is True:
# Save the lookup overhead in __init__ if we need to circumvent
# immutability.
globs["_cached_setattr"] = _obj_setattr
eval(bytecode, globs, locs)
# In order of debuggers like PDB being able to step through the code,
@@ -1245,24 +1304,10 @@ def _make_init(attrs, post_init, frozen, slots, cache_hash, base_attr_map):
__init__ = locs["__init__"]
__init__.__annotations__ = annotations
return __init__
def _add_init(cls, frozen):
"""
Add a __init__ method to *cls*. If *frozen* is True, make it immutable.
"""
cls.__init__ = _make_init(
cls.__attrs_attrs__,
getattr(cls, "__attrs_post_init__", False),
frozen,
_is_slot_cls(cls),
cache_hash=False,
base_attr_map={},
)
return cls
def fields(cls):
"""
Return the tuple of ``attrs`` attributes for a class.
@@ -1348,7 +1393,7 @@ def _is_slot_attr(a_name, base_attr_map):
def _attrs_to_init_script(
attrs, frozen, slots, post_init, cache_hash, base_attr_map
attrs, frozen, slots, post_init, cache_hash, base_attr_map, is_exc
):
"""
Return a script of an initializer for *attrs* and a dict of globals.
@@ -1597,6 +1642,13 @@ def _attrs_to_init_script(
init_hash_cache = "self.%s = %s"
lines.append(init_hash_cache % (_hash_cache_field, "None"))
# For exceptions we rely on BaseException.__init__ for proper
# initialization.
if is_exc:
vals = ",".join("self." + a.name for a in attrs if a.init)
lines.append("BaseException.__init__(self, %s)" % (vals,))
args = ", ".join(args)
if kw_only_args:
if PY2:
+3 -3
View File
@@ -1,5 +1,5 @@
from typing import Union
from typing import Union, Any
from . import Attribute, _FilterType
def include(*what: Union[type, Attribute]) -> _FilterType: ...
def exclude(*what: Union[type, Attribute]) -> _FilterType: ...
def include(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ...
def exclude(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ...
+113 -1
View File
@@ -136,7 +136,7 @@ class _InValidator(object):
def __call__(self, inst, attr, value):
try:
in_options = value in self.options
except TypeError as e: # e.g. `1 in "abc"`
except TypeError: # e.g. `1 in "abc"`
in_options = False
if not in_options:
@@ -168,3 +168,115 @@ def in_(options):
.. versionadded:: 17.1.0
"""
return _InValidator(options)
@attrs(repr=False, slots=False, hash=True)
class _IsCallableValidator(object):
def __call__(self, inst, attr, value):
"""
We use a callable class to be able to change the ``__repr__``.
"""
if not callable(value):
raise TypeError("'{name}' must be callable".format(name=attr.name))
def __repr__(self):
return "<is_callable validator>"
def is_callable():
"""
A validator that raises a :class:`TypeError` if the initializer is called
with a value for this particular attribute that is not callable.
.. versionadded:: 19.1.0
:raises TypeError: With a human readable error message containing the
attribute (of type :class:`attr.Attribute`) name.
"""
return _IsCallableValidator()
@attrs(repr=False, slots=True, hash=True)
class _DeepIterable(object):
member_validator = attrib(validator=is_callable())
iterable_validator = attrib(
default=None, validator=optional(is_callable())
)
def __call__(self, inst, attr, value):
"""
We use a callable class to be able to change the ``__repr__``.
"""
if self.iterable_validator is not None:
self.iterable_validator(inst, attr, value)
for member in value:
self.member_validator(inst, attr, member)
def __repr__(self):
iterable_identifier = (
""
if self.iterable_validator is None
else " {iterable!r}".format(iterable=self.iterable_validator)
)
return (
"<deep_iterable validator for{iterable_identifier}"
" iterables of {member!r}>"
).format(
iterable_identifier=iterable_identifier,
member=self.member_validator,
)
def deep_iterable(member_validator, iterable_validator=None):
"""
A validator that performs deep validation of an iterable.
:param member_validator: Validator to apply to iterable members
:param iterable_validator: Validator to apply to iterable itself
(optional)
.. versionadded:: 19.1.0
:raises TypeError: if any sub-validators fail
"""
return _DeepIterable(member_validator, iterable_validator)
@attrs(repr=False, slots=True, hash=True)
class _DeepMapping(object):
key_validator = attrib(validator=is_callable())
value_validator = attrib(validator=is_callable())
mapping_validator = attrib(default=None, validator=optional(is_callable()))
def __call__(self, inst, attr, value):
"""
We use a callable class to be able to change the ``__repr__``.
"""
if self.mapping_validator is not None:
self.mapping_validator(inst, attr, value)
for key in value:
self.key_validator(inst, attr, key)
self.value_validator(inst, attr, value[key])
def __repr__(self):
return (
"<deep_mapping validator for objects mapping {key!r} to {value!r}>"
).format(key=self.key_validator, value=self.value_validator)
def deep_mapping(key_validator, value_validator, mapping_validator=None):
"""
A validator that performs deep validation of a dictionary.
:param key_validator: Validator to apply to dictionary keys
:param value_validator: Validator to apply to dictionary values
:param mapping_validator: Validator to apply to top-level mapping
attribute (optional)
.. versionadded:: 19.1.0
:raises TypeError: if any sub-validators fail
"""
return _DeepMapping(key_validator, value_validator, mapping_validator)
+10
View File
@@ -12,3 +12,13 @@ def optional(
) -> _ValidatorType[Optional[_T]]: ...
def in_(options: Container[_T]) -> _ValidatorType[_T]: ...
def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ...
def deep_iterable(
member_validator: _ValidatorType[_T],
iterable_validator: Optional[_ValidatorType[_T]],
) -> _ValidatorType[_T]: ...
def deep_mapping(
key_validator: _ValidatorType[_T],
value_validator: _ValidatorType[_T],
mapping_validator: Optional[_ValidatorType[_T]],
) -> _ValidatorType[_T]: ...
def is_callable() -> _ValidatorType[_T]: ...
+1 -1
View File
@@ -2,7 +2,7 @@
__author__ = "Daniel Greenfeld"
__email__ = "pydanny@gmail.com"
__version__ = "1.4.3"
__version__ = "1.5.1"
__license__ = "BSD"
from time import time
+2 -2
View File
@@ -1,3 +1,3 @@
from .core import where, old_where
from .core import where
__version__ = "2018.10.15"
__version__ = "2018.11.29"
+242
View File
@@ -4268,3 +4268,245 @@ rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV
57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg
Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
-----END CERTIFICATE-----
# Issuer: CN=GTS Root R1 O=Google Trust Services LLC
# Subject: CN=GTS Root R1 O=Google Trust Services LLC
# Label: "GTS Root R1"
# Serial: 146587175971765017618439757810265552097
# MD5 Fingerprint: 82:1a:ef:d4:d2:4a:f2:9f:e2:3d:97:06:14:70:72:85
# SHA1 Fingerprint: e1:c9:50:e6:ef:22:f8:4c:56:45:72:8b:92:20:60:d7:d5:a7:a3:e8
# SHA256 Fingerprint: 2a:57:54:71:e3:13:40:bc:21:58:1c:bd:2c:f1:3e:15:84:63:20:3e:ce:94:bc:f9:d3:cc:19:6b:f0:9a:54:72
-----BEGIN CERTIFICATE-----
MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy
MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl
cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM
f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX
mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7
zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P
fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc
vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4
Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp
zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO
Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW
k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+
DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF
lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW
Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1
d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z
XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR
gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3
d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv
J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg
DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM
+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy
F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9
SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws
E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl
-----END CERTIFICATE-----
# Issuer: CN=GTS Root R2 O=Google Trust Services LLC
# Subject: CN=GTS Root R2 O=Google Trust Services LLC
# Label: "GTS Root R2"
# Serial: 146587176055767053814479386953112547951
# MD5 Fingerprint: 44:ed:9a:0e:a4:09:3b:00:f2:ae:4c:a3:c6:61:b0:8b
# SHA1 Fingerprint: d2:73:96:2a:2a:5e:39:9f:73:3f:e1:c7:1e:64:3f:03:38:34:fc:4d
# SHA256 Fingerprint: c4:5d:7b:b0:8e:6d:67:e6:2e:42:35:11:0b:56:4e:5f:78:fd:92:ef:05:8c:84:0a:ea:4e:64:55:d7:58:5c:60
-----BEGIN CERTIFICATE-----
MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy
MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl
cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv
CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg
GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu
XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd
re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu
PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1
mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K
8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj
x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR
nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0
kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok
twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp
8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT
vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT
z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA
pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb
pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB
R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R
RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk
0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC
5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF
izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn
yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC
-----END CERTIFICATE-----
# Issuer: CN=GTS Root R3 O=Google Trust Services LLC
# Subject: CN=GTS Root R3 O=Google Trust Services LLC
# Label: "GTS Root R3"
# Serial: 146587176140553309517047991083707763997
# MD5 Fingerprint: 1a:79:5b:6b:04:52:9c:5d:c7:74:33:1b:25:9a:f9:25
# SHA1 Fingerprint: 30:d4:24:6f:07:ff:db:91:89:8a:0b:e9:49:66:11:eb:8c:5e:46:e5
# SHA256 Fingerprint: 15:d5:b8:77:46:19:ea:7d:54:ce:1c:a6:d0:b0:c4:03:e0:37:a9:17:f1:31:e8:a0:4e:1e:6b:7a:71:ba:bc:e5
-----BEGIN CERTIFICATE-----
MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA
IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout
736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A
DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk
fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA
njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd
-----END CERTIFICATE-----
# Issuer: CN=GTS Root R4 O=Google Trust Services LLC
# Subject: CN=GTS Root R4 O=Google Trust Services LLC
# Label: "GTS Root R4"
# Serial: 146587176229350439916519468929765261721
# MD5 Fingerprint: 5d:b6:6a:c4:60:17:24:6a:1a:99:a8:4b:ee:5e:b4:26
# SHA1 Fingerprint: 2a:1d:60:27:d9:4a:b1:0a:1c:4d:91:5c:cd:33:a0:cb:3e:2d:54:cb
# SHA256 Fingerprint: 71:cc:a5:39:1f:9e:79:4b:04:80:25:30:b3:63:e1:21:da:8a:30:43:bb:26:66:2f:ea:4d:ca:7f:c9:51:a4:bd
-----BEGIN CERTIFICATE-----
MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA
IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu
hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l
xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0
CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx
sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w==
-----END CERTIFICATE-----
# Issuer: CN=UCA Global G2 Root O=UniTrust
# Subject: CN=UCA Global G2 Root O=UniTrust
# Label: "UCA Global G2 Root"
# Serial: 124779693093741543919145257850076631279
# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8
# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a
# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c
-----BEGIN CERTIFICATE-----
MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9
MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH
bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x
CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds
b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr
b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9
kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm
VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R
VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc
C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj
tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY
D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv
j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl
NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6
iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP
O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/
BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV
ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj
L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5
1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl
1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU
b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV
PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj
y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb
EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg
DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI
+Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy
YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX
UB+K+wb1whnw0A==
-----END CERTIFICATE-----
# Issuer: CN=UCA Extended Validation Root O=UniTrust
# Subject: CN=UCA Extended Validation Root O=UniTrust
# Label: "UCA Extended Validation Root"
# Serial: 106100277556486529736699587978573607008
# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2
# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a
# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24
-----BEGIN CERTIFICATE-----
MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH
MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF
eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx
MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV
BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog
D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS
sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop
O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk
sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi
c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj
VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz
KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/
TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G
sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs
1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD
fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T
AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN
l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR
ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ
VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5
c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp
4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s
t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj
2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO
vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C
xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx
cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM
fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax
-----END CERTIFICATE-----
# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036
# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036
# Label: "Certigna Root CA"
# Serial: 269714418870597844693661054334862075617
# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77
# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43
# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68
-----BEGIN CERTIFICATE-----
MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw
WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw
MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x
MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD
VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX
BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO
ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M
CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu
I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm
TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh
C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf
ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz
IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT
Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k
JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5
hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB
GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of
1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov
L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo
dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr
aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq
hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L
6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG
HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6
0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB
lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi
o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1
gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v
faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63
Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh
jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw
3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0=
-----END CERTIFICATE-----
-17
View File
@@ -8,14 +8,6 @@ certifi.py
This module returns the installation location of cacert.pem.
"""
import os
import warnings
class DeprecatedBundleWarning(DeprecationWarning):
"""
The weak security bundle is being deprecated. Please bother your service
provider to get them to stop using cross-signed roots.
"""
def where():
@@ -24,14 +16,5 @@ def where():
return os.path.join(f, 'cacert.pem')
def old_where():
warnings.warn(
"The weak security bundle has been removed. certifi.old_where() is now an alias "
"of certifi.where(). Please update your code to use certifi.where() instead. "
"certifi.old_where() will be removed in 2018.",
DeprecatedBundleWarning
)
return where()
if __name__ == '__main__':
print(where())
-1
View File
@@ -25,4 +25,3 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+1 -2
View File
@@ -3,5 +3,4 @@ from .initialise import init, deinit, reinit, colorama_text
from .ansi import Fore, Back, Style, Cursor
from .ansitowin32 import AnsiToWin32
__version__ = '0.3.9'
__version__ = '0.4.1'
+32 -11
View File
@@ -13,14 +13,6 @@ if windll is not None:
winterm = WinTerm()
def is_stream_closed(stream):
return not hasattr(stream, 'closed') or stream.closed
def is_a_tty(stream):
return hasattr(stream, 'isatty') and stream.isatty()
class StreamWrapper(object):
'''
Wraps a stream (such as stdout), acting as a transparent proxy for all
@@ -36,9 +28,38 @@ class StreamWrapper(object):
def __getattr__(self, name):
return getattr(self.__wrapped, name)
def __enter__(self, *args, **kwargs):
# special method lookup bypasses __getattr__/__getattribute__, see
# https://stackoverflow.com/questions/12632894/why-doesnt-getattr-work-with-exit
# thus, contextlib magic methods are not proxied via __getattr__
return self.__wrapped.__enter__(*args, **kwargs)
def __exit__(self, *args, **kwargs):
return self.__wrapped.__exit__(*args, **kwargs)
def write(self, text):
self.__convertor.write(text)
def isatty(self):
stream = self.__wrapped
if 'PYCHARM_HOSTED' in os.environ:
if stream is not None and (stream is sys.__stdout__ or stream is sys.__stderr__):
return True
try:
stream_isatty = stream.isatty
except AttributeError:
return False
else:
return stream_isatty()
@property
def closed(self):
stream = self.__wrapped
try:
return stream.closed
except AttributeError:
return True
class AnsiToWin32(object):
'''
@@ -68,12 +89,12 @@ class AnsiToWin32(object):
# should we strip ANSI sequences from our output?
if strip is None:
strip = conversion_supported or (not is_stream_closed(wrapped) and not is_a_tty(wrapped))
strip = conversion_supported or (not self.stream.closed and not self.stream.isatty())
self.strip = strip
# should we should convert ANSI sequences into win32 calls?
if convert is None:
convert = conversion_supported and not is_stream_closed(wrapped) and is_a_tty(wrapped)
convert = conversion_supported and not self.stream.closed and self.stream.isatty()
self.convert = convert
# dict of ansi codes to win32 functions and parameters
@@ -149,7 +170,7 @@ class AnsiToWin32(object):
def reset_all(self):
if self.convert:
self.call_win32('m', (0,))
elif not self.strip and not is_stream_closed(self.wrapped):
elif not self.strip and not self.stream.closed:
self.wrapped.write(Style.RESET_ALL)

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