mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 06:46:15 +00:00
Issue 4993 Add standard pre commit hooks and apply linting. (#4994)
* Add .pre-commit-config.yaml to the project and exclude tests (for now). This does not include the MyPy linting that pip does but does include everything else.
This commit is contained in:
@@ -72,6 +72,14 @@ jobs:
|
||||
git submodule update --init --recursive
|
||||
python -m pip install -e . --upgrade
|
||||
pipenv install --deploy --dev --python=${{ steps.python-path.outputs.path }}
|
||||
- name: Lint check of the code
|
||||
env:
|
||||
PIPENV_DEFAULT_PYTHON_VERSION: ${{ matrix.python-version }}
|
||||
PYTHONWARNINGS: ignore:DEPRECATION
|
||||
PYTHONIOENCODING: "utf-8"
|
||||
GIT_ASK_YESNO: "false"
|
||||
run: |
|
||||
pipenv run pre-commit run --all-files --verbose
|
||||
- name: Run tests
|
||||
env:
|
||||
PIPENV_DEFAULT_PYTHON_VERSION: ${{ matrix.python-version }}
|
||||
@@ -109,4 +117,3 @@ jobs:
|
||||
- run: |
|
||||
python -m pip install --upgrade wheel invoke parver bs4 vistir towncrier
|
||||
python -m invoke vendoring.update
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[settings]
|
||||
profile = black
|
||||
@@ -0,0 +1,64 @@
|
||||
exclude: '^(pipenv/patched/|pipenv/vendor/|tests/)'
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.1.0
|
||||
hooks:
|
||||
- id: check-builtin-literals
|
||||
- id: check-added-large-files
|
||||
- id: check-case-conflict
|
||||
- id: check-ast
|
||||
- id: check-toml
|
||||
- id: check-yaml
|
||||
- id: debug-statements
|
||||
- id: end-of-file-fixer
|
||||
exclude: WHEEL
|
||||
- id: forbid-new-submodules
|
||||
- id: trailing-whitespace
|
||||
exclude: .patch
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.3.0
|
||||
hooks:
|
||||
- id: black
|
||||
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 4.0.1
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies: [
|
||||
'flake8-bugbear==20.1.4',
|
||||
'flake8-logging-format==0.6.0',
|
||||
'flake8-implicit-str-concat==0.2.0',
|
||||
]
|
||||
exclude: tests/data
|
||||
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 5.10.1
|
||||
hooks:
|
||||
- id: isort
|
||||
files: \.py$
|
||||
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: v1.7.0
|
||||
hooks:
|
||||
- id: python-no-log-warn
|
||||
- id: python-no-eval
|
||||
- id: rst-backticks
|
||||
files: .*\.rst$
|
||||
types: [file]
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: news-fragment-filenames
|
||||
name: NEWS fragment
|
||||
language: fail
|
||||
entry: NEWS fragment files must be named *.(feature|behavior|bugfix|vendor|doc|trivial|removal|process).rst
|
||||
exclude: ^news/(towncrier_template.rst|.*\.(feature|behavior|bugfix|vendor|doc|trivial|removal|process).rst)
|
||||
files: ^news/
|
||||
|
||||
- repo: https://github.com/mgedmin/check-manifest
|
||||
rev: '0.46'
|
||||
hooks:
|
||||
- id: check-manifest
|
||||
stages: [manual]
|
||||
+16
-16
@@ -5,7 +5,7 @@
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Environment variables were not being loaded when the `--quiet` flag was set `#5010 <https://github.com/pypa/pipenv/issues/5010>`_
|
||||
- Environment variables were not being loaded when the ``--quiet`` flag was set `#5010 <https://github.com/pypa/pipenv/issues/5010>`_
|
||||
- It would appear that ``requirementslib`` was not fully specifying the subdirectory to ``build_pep517`` and
|
||||
and when a new version of ``setuptools`` was released, the test ``test_lock_nested_vcs_direct_url``
|
||||
broke indicating the Pipfile.lock no longer contained the extra dependencies that should have been resolved.
|
||||
@@ -25,7 +25,7 @@ Features & Improvements
|
||||
-----------------------
|
||||
|
||||
- It is now possible to silence the ``Loading .env environment variables`` message on ``pipenv run``
|
||||
with the ``--quiet`` flag or the `PIPENV_QUIET` environment variable. `#4027 <https://github.com/pypa/pipenv/issues/4027>`_
|
||||
with the ``--quiet`` flag or the ``PIPENV_QUIET`` environment variable. `#4027 <https://github.com/pypa/pipenv/issues/4027>`_
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
@@ -43,7 +43,7 @@ Bug Fixes
|
||||
Features & Improvements
|
||||
-----------------------
|
||||
|
||||
- Use environment variable `PIPENV_SKIP_LOCK` to control the behaviour of lock skipping. `#4797 <https://github.com/pypa/pipenv/issues/4797>`_
|
||||
- Use environment variable ``PIPENV_SKIP_LOCK`` to control the behaviour of lock skipping. `#4797 <https://github.com/pypa/pipenv/issues/4797>`_
|
||||
- New CLI command ``verify``, checks the Pipfile.lock is up-to-date `#4893 <https://github.com/pypa/pipenv/issues/4893>`_
|
||||
|
||||
Behavior Changes
|
||||
@@ -56,15 +56,15 @@ Bug Fixes
|
||||
|
||||
- Python versions on Windows can now be installed automatically through pyenv-win `#4525 <https://github.com/pypa/pipenv/issues/4525>`_
|
||||
- Patched our vendored Pip to fix: Pipenv Lock (Or Install) Does Not Respect Index Specified For A Package. `#4637 <https://github.com/pypa/pipenv/issues/4637>`_
|
||||
- If `PIP_TARGET` is set to environment variables, Refer specified directory for calculate delta, instead default directory `#4775 <https://github.com/pypa/pipenv/issues/4775>`_
|
||||
- If ``PIP_TARGET`` is set to environment variables, Refer specified directory for calculate delta, instead default directory `#4775 <https://github.com/pypa/pipenv/issues/4775>`_
|
||||
- Remove remaining mention of python2 and --two flag from codebase. `#4938 <https://github.com/pypa/pipenv/issues/4938>`_
|
||||
- Use `CI` environment value, over mere existence of name `#4944 <https://github.com/pypa/pipenv/issues/4944>`_
|
||||
- Use ``CI`` environment value, over mere existence of name `#4944 <https://github.com/pypa/pipenv/issues/4944>`_
|
||||
- Environment variables from dot env files are now properly expanded when included in scripts. `#4975 <https://github.com/pypa/pipenv/issues/4975>`_
|
||||
|
||||
Vendored Libraries
|
||||
------------------
|
||||
|
||||
- Updated vendor version of `pythonfinder` from `1.2.9` to `1.2.10` which fixes a bug with WSL
|
||||
- Updated vendor version of ``pythonfinder`` from ``1.2.9`` to ``1.2.10`` which fixes a bug with WSL
|
||||
(Windows Subsystem for Linux) when a path can not be read and Permission Denied error is encountered. `#4976 <https://github.com/pypa/pipenv/issues/4976>`_
|
||||
|
||||
Removals and Deprecations
|
||||
@@ -207,7 +207,7 @@ Vendored Libraries
|
||||
- ``tomli 1.1.0``
|
||||
- ``wheel 0.36.2`` `#4747 <https://github.com/pypa/pipenv/issues/4747>`_
|
||||
- Drop the dependencies for Python 2.7 compatibility purpose. `#4751 <https://github.com/pypa/pipenv/issues/4751>`_
|
||||
- Switch the dependency resolver from ``pip-tools`` to `pip`.
|
||||
- Switch the dependency resolver from ``pip-tools`` to ``pip``.
|
||||
|
||||
Update vendor libraries:
|
||||
- Update ``requirementslib`` from ``1.5.16`` to ``1.6.1``
|
||||
@@ -416,7 +416,7 @@ Features & Improvements
|
||||
- Allow overriding PIPENV_INSTALL_TIMEOUT environment variable (in seconds). `#3652 <https://github.com/pypa/pipenv/issues/3652>`_
|
||||
- Allow overriding PIP_EXISTS_ACTION evironment variable (value is passed to pip install).
|
||||
Possible values here: https://pip.pypa.io/en/stable/reference/pip/#exists-action-option
|
||||
Useful when you need to `PIP_EXISTS_ACTION=i` (ignore existing packages) - great for CI environments, where you need really fast setup. `#3738 <https://github.com/pypa/pipenv/issues/3738>`_
|
||||
Useful when you need to ``PIP_EXISTS_ACTION=i`` (ignore existing packages) - great for CI environments, where you need really fast setup. `#3738 <https://github.com/pypa/pipenv/issues/3738>`_
|
||||
- Pipenv will no longer forcibly override ``PIP_NO_DEPS`` on all vcs and file dependencies as resolution happens on these in a pre-lock step. `#3763 <https://github.com/pypa/pipenv/issues/3763>`_
|
||||
- Improved verbose logging output during ``pipenv lock`` will now stream output to the console while maintaining a spinner. `#3810 <https://github.com/pypa/pipenv/issues/3810>`_
|
||||
- Added support for automatic python installs via ``asdf`` and associated ``PIPENV_DONT_USE_ASDF`` environment variable. `#4018 <https://github.com/pypa/pipenv/issues/4018>`_
|
||||
@@ -434,7 +434,7 @@ Behavior Changes
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Raise `PipenvUsageError` when [[source]] does not contain url field. `#2373 <https://github.com/pypa/pipenv/issues/2373>`_
|
||||
- Raise ``PipenvUsageError`` when [[source]] does not contain url field. `#2373 <https://github.com/pypa/pipenv/issues/2373>`_
|
||||
- Fixed a bug which caused editable package resolution to sometimes fail with an unhelpful setuptools-related error message. `#2722 <https://github.com/pypa/pipenv/issues/2722>`_
|
||||
- Fixed an issue which caused errors due to reliance on the system utilities ``which`` and ``where`` which may not always exist on some systems.
|
||||
- Fixed a bug which caused periodic failures in python discovery when executables named ``python`` were not present on the target ``$PATH``. `#2783 <https://github.com/pypa/pipenv/issues/2783>`_
|
||||
@@ -697,13 +697,13 @@ Bug Fixes
|
||||
- Fixed an issue in ``delegator.py`` related to subprocess calls when using ``PopenSpawn`` to stream output, which sometimes threw unexpected ``EOF`` errors. `#3102 <https://github.com/pypa/pipenv/issues/3102>`_,
|
||||
`#3114 <https://github.com/pypa/pipenv/issues/3114>`_,
|
||||
`#3117 <https://github.com/pypa/pipenv/issues/3117>`_
|
||||
- Fix the path casing issue that makes `pipenv clean` fail on Windows `#3104 <https://github.com/pypa/pipenv/issues/3104>`_
|
||||
- Fix the path casing issue that makes ``pipenv clean`` fail on Windows `#3104 <https://github.com/pypa/pipenv/issues/3104>`_
|
||||
- Pipenv will avoid leaving build artifacts in the current working directory. `#3106 <https://github.com/pypa/pipenv/issues/3106>`_
|
||||
- Fixed issues with broken subprocess calls leaking resource handles and causing random and sporadic failures. `#3109 <https://github.com/pypa/pipenv/issues/3109>`_
|
||||
- Fixed an issue which caused ``pipenv clean`` to sometimes clean packages from the base ``site-packages`` folder or fail entirely. `#3113 <https://github.com/pypa/pipenv/issues/3113>`_
|
||||
- Updated ``pythonfinder`` to correct an issue with unnesting of nested paths when searching for python versions. `#3121 <https://github.com/pypa/pipenv/issues/3121>`_
|
||||
- Added additional logic for ignoring and replacing non-ascii characters when formatting console output on non-UTF-8 systems. `#3131 <https://github.com/pypa/pipenv/issues/3131>`_
|
||||
- Fix virtual environment discovery when ``PIPENV_VENV_IN_PROJECT`` is set, but the in-project `.venv` is a file. `#3134 <https://github.com/pypa/pipenv/issues/3134>`_
|
||||
- Fix virtual environment discovery when ``PIPENV_VENV_IN_PROJECT`` is set, but the in-project ``.venv`` is a file. `#3134 <https://github.com/pypa/pipenv/issues/3134>`_
|
||||
- Hashes for remote and local non-PyPI artifacts will now be included in ``Pipfile.lock`` during resolution. `#3145 <https://github.com/pypa/pipenv/issues/3145>`_
|
||||
- Fix project path hashing logic in purpose to prevent collisions of virtual environments. `#3151 <https://github.com/pypa/pipenv/issues/3151>`_
|
||||
- Fix package installation when the virtual environment path contains parentheses. `#3158 <https://github.com/pypa/pipenv/issues/3158>`_
|
||||
@@ -787,7 +787,7 @@ Vendored Libraries
|
||||
Features & Improvements
|
||||
-----------------------
|
||||
|
||||
- Added environment variables `PIPENV_VERBOSE` and `PIPENV_QUIET` to control
|
||||
- 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 add-on to better support json-API access (forward compatibility).
|
||||
@@ -820,7 +820,7 @@ Behavior Changes
|
||||
- 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>`_
|
||||
- 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
|
||||
@@ -918,7 +918,7 @@ Bug Fixes
|
||||
`#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 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>`_
|
||||
|
||||
@@ -985,7 +985,7 @@ Improved Documentation
|
||||
|
||||
- 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>`_
|
||||
- Stopped recommending ``--system`` for Docker contexts. `#2762 <https://github.com/pypa/pipenv/issues/2762>`_
|
||||
|
||||
- Fixed the example url for doing "pipenv install -e
|
||||
some-repository-url#egg=something", it was missing the "egg=" in the fragment
|
||||
@@ -993,7 +993,7 @@ Improved Documentation
|
||||
|
||||
- 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>`_
|
||||
- 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>`_
|
||||
|
||||
|
||||
@@ -5,7 +5,10 @@ click = "*"
|
||||
pytest_pypi = {path = "./tests/pytest-pypi", editable = true}
|
||||
stdeb = {version="*", markers="sys_platform == 'linux'"}
|
||||
dataclasses = {version="*", markers="python_version < '3.7'"}
|
||||
importlib-resources = {version = "*", markers = "python_version < '3.7'"}
|
||||
sphinxcontrib-spelling = "<4.3.0"
|
||||
pre-commit = "*"
|
||||
atomicwrites = {version = "*", markers="sys_platform == 'win32'"}
|
||||
|
||||
[packages]
|
||||
|
||||
|
||||
Generated
+292
-180
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "b6632ccfba082244f188747d88665264be87621552d2c1bbebaf36174bc24e8a"
|
||||
"sha256": "0d25587c8b692005c51421eb35b08c878ca1d6e14e175d3c9ed74fd4d637476d"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
@@ -39,11 +39,11 @@
|
||||
},
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
|
||||
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
|
||||
"sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4",
|
||||
"sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==21.2.0"
|
||||
"version": "==21.4.0"
|
||||
},
|
||||
"babel": {
|
||||
"hashes": [
|
||||
@@ -53,14 +53,6 @@
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.9.1"
|
||||
},
|
||||
"backports.entry-points-selectable": {
|
||||
"hashes": [
|
||||
"sha256:7fceed9532a7aa2bd888654a7314f864a3c16a4e710b34a58cfc0f08114c663b",
|
||||
"sha256:914b21a479fde881635f7af5adc7f6e38d6b274be32269070c53b698c60d5386"
|
||||
],
|
||||
"markers": "python_version >= '2.7'",
|
||||
"version": "==1.1.1"
|
||||
},
|
||||
"beautifulsoup4": {
|
||||
"hashes": [
|
||||
"sha256:9a315ce70049920ea4572a4055bc4bd700c940521d36fc858205ad4fcde149bf",
|
||||
@@ -71,11 +63,11 @@
|
||||
},
|
||||
"black": {
|
||||
"hashes": [
|
||||
"sha256:0b1f66cbfadcd332ceeaeecf6373d9991d451868d2e2219ad0ac1213fb701117",
|
||||
"sha256:83f3852301c8dcb229e9c444dd79f573c8d31c7c2dad9bbaaa94c808630e32aa"
|
||||
"sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3",
|
||||
"sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"
|
||||
],
|
||||
"markers": "python_full_version >= '3.6.2'",
|
||||
"version": "==21.11b0"
|
||||
"version": "==21.12b0"
|
||||
},
|
||||
"bleach": {
|
||||
"hashes": [
|
||||
@@ -98,13 +90,76 @@
|
||||
],
|
||||
"version": "==2021.10.8"
|
||||
},
|
||||
"cffi": {
|
||||
"hashes": [
|
||||
"sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3",
|
||||
"sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2",
|
||||
"sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636",
|
||||
"sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20",
|
||||
"sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728",
|
||||
"sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27",
|
||||
"sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66",
|
||||
"sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443",
|
||||
"sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0",
|
||||
"sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7",
|
||||
"sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39",
|
||||
"sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605",
|
||||
"sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a",
|
||||
"sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37",
|
||||
"sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029",
|
||||
"sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139",
|
||||
"sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc",
|
||||
"sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df",
|
||||
"sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14",
|
||||
"sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880",
|
||||
"sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2",
|
||||
"sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a",
|
||||
"sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e",
|
||||
"sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474",
|
||||
"sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024",
|
||||
"sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8",
|
||||
"sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0",
|
||||
"sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e",
|
||||
"sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a",
|
||||
"sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e",
|
||||
"sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032",
|
||||
"sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6",
|
||||
"sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e",
|
||||
"sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b",
|
||||
"sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e",
|
||||
"sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954",
|
||||
"sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962",
|
||||
"sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c",
|
||||
"sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4",
|
||||
"sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55",
|
||||
"sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962",
|
||||
"sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023",
|
||||
"sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c",
|
||||
"sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6",
|
||||
"sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8",
|
||||
"sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382",
|
||||
"sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7",
|
||||
"sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc",
|
||||
"sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997",
|
||||
"sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"
|
||||
],
|
||||
"version": "==1.15.0"
|
||||
},
|
||||
"cfgv": {
|
||||
"hashes": [
|
||||
"sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426",
|
||||
"sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"
|
||||
],
|
||||
"markers": "python_full_version >= '3.6.1'",
|
||||
"version": "==3.3.1"
|
||||
},
|
||||
"charset-normalizer": {
|
||||
"hashes": [
|
||||
"sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0",
|
||||
"sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"
|
||||
"sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597",
|
||||
"sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"
|
||||
],
|
||||
"markers": "python_version >= '3.0'",
|
||||
"version": "==2.0.7"
|
||||
"version": "==2.0.12"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
@@ -125,9 +180,35 @@
|
||||
"sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b",
|
||||
"sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"
|
||||
],
|
||||
"markers": "sys_platform == 'win32'",
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==0.4.4"
|
||||
},
|
||||
"cryptography": {
|
||||
"hashes": [
|
||||
"sha256:0a3bf09bb0b7a2c93ce7b98cb107e9170a90c51a0162a20af1c61c765b90e60b",
|
||||
"sha256:1f64a62b3b75e4005df19d3b5235abd43fa6358d5516cfc43d87aeba8d08dd51",
|
||||
"sha256:32db5cc49c73f39aac27574522cecd0a4bb7384e71198bc65a0d23f901e89bb7",
|
||||
"sha256:4881d09298cd0b669bb15b9cfe6166f16fc1277b4ed0d04a22f3d6430cb30f1d",
|
||||
"sha256:4e2dddd38a5ba733be6a025a1475a9f45e4e41139d1321f412c6b360b19070b6",
|
||||
"sha256:53e0285b49fd0ab6e604f4c5d9c5ddd98de77018542e88366923f152dbeb3c29",
|
||||
"sha256:70f8f4f7bb2ac9f340655cbac89d68c527af5bb4387522a8413e841e3e6628c9",
|
||||
"sha256:7b2d54e787a884ffc6e187262823b6feb06c338084bbe80d45166a1cb1c6c5bf",
|
||||
"sha256:7be666cc4599b415f320839e36367b273db8501127b38316f3b9f22f17a0b815",
|
||||
"sha256:8241cac0aae90b82d6b5c443b853723bcc66963970c67e56e71a2609dc4b5eaf",
|
||||
"sha256:82740818f2f240a5da8dfb8943b360e4f24022b093207160c77cadade47d7c85",
|
||||
"sha256:8897b7b7ec077c819187a123174b645eb680c13df68354ed99f9b40a50898f77",
|
||||
"sha256:c2c5250ff0d36fd58550252f54915776940e4e866f38f3a7866d92b32a654b86",
|
||||
"sha256:ca9f686517ec2c4a4ce930207f75c00bf03d94e5063cbc00a1dc42531511b7eb",
|
||||
"sha256:d2b3d199647468d410994dbeb8cec5816fb74feb9368aedf300af709ef507e3e",
|
||||
"sha256:da73d095f8590ad437cd5e9faf6628a218aa7c387e1fdf67b888b47ba56a17f0",
|
||||
"sha256:e167b6b710c7f7bc54e67ef593f8731e1f45aa35f8a8a7b72d6e42ec76afd4b3",
|
||||
"sha256:ea634401ca02367c1567f012317502ef3437522e2fc44a3ea1844de028fa4b84",
|
||||
"sha256:ec6597aa85ce03f3e507566b8bcdf9da2227ec86c4266bd5e6ab4d9e0cc8dab2",
|
||||
"sha256:f64b232348ee82f13aac22856515ce0195837f6968aeaa94a3d0353ea2ec06a6"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==36.0.2"
|
||||
},
|
||||
"dataclasses": {
|
||||
"hashes": [
|
||||
"sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf",
|
||||
@@ -139,10 +220,10 @@
|
||||
},
|
||||
"distlib": {
|
||||
"hashes": [
|
||||
"sha256:c8b54e8454e5bf6237cc84c20e8264c3e991e824ef27e8f1e81049867d861e31",
|
||||
"sha256:d982d0751ff6eaaab5e2ec8e691d949ee80eddf01a62eaa96ddb11531fe16b05"
|
||||
"sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b",
|
||||
"sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"
|
||||
],
|
||||
"version": "==0.3.3"
|
||||
"version": "==0.3.4"
|
||||
},
|
||||
"docutils": {
|
||||
"hashes": [
|
||||
@@ -162,11 +243,11 @@
|
||||
},
|
||||
"filelock": {
|
||||
"hashes": [
|
||||
"sha256:2e139a228bcf56dd8b2274a65174d005c4a6b68540ee0bdbb92c76f43f29f7e8",
|
||||
"sha256:93d512b32a23baf4cac44ffd72ccf70732aeff7b8050fcaf6d3ec406d954baf4"
|
||||
"sha256:0f12f552b42b5bf60dba233710bf71337d35494fc8bdd4fd6d9f6d082ad45e06",
|
||||
"sha256:a4bc51381e01502a30e9f06dd4fa19a1712eab852b6fb0f84fd7cce0793d8ca3"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.4.0"
|
||||
"version": "==3.4.1"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
@@ -186,11 +267,19 @@
|
||||
},
|
||||
"flask": {
|
||||
"hashes": [
|
||||
"sha256:7b2fb8e934ddd50731893bdcdb00fc8c0315916f9fcd50d22c7cc1a95ab634e2",
|
||||
"sha256:cb90f62f1d8e4dc4621f52106613488b5ba826b2e1e10a33eac92f723093ab6a"
|
||||
"sha256:59da8a3170004800a2837844bfa84d49b022550616070f7cb1a659682b2e7c9f",
|
||||
"sha256:e1120c228ca2f553b470df4a5fa927ab66258467526069981b3eb0a91902687d"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.2"
|
||||
"version": "==2.0.3"
|
||||
},
|
||||
"identify": {
|
||||
"hashes": [
|
||||
"sha256:6b4b5031f69c48bf93a646b90de9b381c6b5f560df4cbe0ed3cf7650ae741e4d",
|
||||
"sha256:aa68609c7454dbcaae60a01ff6b8df1de9b39fe6e50b1f6107ec81dcda624aa6"
|
||||
],
|
||||
"markers": "python_full_version >= '3.6.1'",
|
||||
"version": "==2.4.4"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
@@ -210,19 +299,20 @@
|
||||
},
|
||||
"importlib-metadata": {
|
||||
"hashes": [
|
||||
"sha256:53ccfd5c134223e497627b9815d5030edf77d2ed573922f7a0b8f8bb81a1c100",
|
||||
"sha256:75bdec14c397f528724c1bfd9709d660b33a4d2e77387a3358f20b848bb5e5fb"
|
||||
"sha256:65a9576a5b2d58ca44d133c42a241905cc45e34d2c06fd5ba2bafa221e5d7b5e",
|
||||
"sha256:766abffff765960fcc18003801f7044eb6755ffae4521c8e8ce8e83b9c9b0668"
|
||||
],
|
||||
"markers": "python_version < '3.8'",
|
||||
"version": "==4.8.2"
|
||||
"version": "==4.8.3"
|
||||
},
|
||||
"importlib-resources": {
|
||||
"hashes": [
|
||||
"sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45",
|
||||
"sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"
|
||||
"sha256:203d70dda34cfbfbb42324a8d4211196e7d3e858de21a5eb68c6d1cdd99e4e98",
|
||||
"sha256:ae35ed1cfe8c0d6c1a53ecd168167f01fa93b893d51a62cdf23aea044c67211b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version < '3.7'",
|
||||
"version": "==5.4.0"
|
||||
"version": "==5.2.3"
|
||||
},
|
||||
"incremental": {
|
||||
"hashes": [
|
||||
@@ -240,11 +330,10 @@
|
||||
},
|
||||
"invoke": {
|
||||
"hashes": [
|
||||
"sha256:374d1e2ecf78981da94bfaf95366216aaec27c2d6a7b7d5818d92da55aa258d3",
|
||||
"sha256:769e90caeb1bd07d484821732f931f1ad8916a38e3f3e618644687fc09cb6317",
|
||||
"sha256:e6c9917a1e3e73e7ea91fdf82d5f151ccfe85bf30cc65cdb892444c02dbb5f74"
|
||||
"sha256:a5159fc63dba6ca2a87a1e33d282b99cea69711b03c64a35bb4e1c53c6c4afa0",
|
||||
"sha256:e332e49de40463f2016315f51df42313855772be86435686156bc18f45b5cc6c"
|
||||
],
|
||||
"version": "==1.6.0"
|
||||
"version": "==1.7.0"
|
||||
},
|
||||
"itsdangerous": {
|
||||
"hashes": [
|
||||
@@ -254,6 +343,14 @@
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.1"
|
||||
},
|
||||
"jeepney": {
|
||||
"hashes": [
|
||||
"sha256:1b5a0ea5c0e7b166b2f5895b91a08c14de8915afda4407fb5022a195224958ac",
|
||||
"sha256:fa9e232dfa0c498bd0b8a3a73b8d8a31978304dcef0515adc859d4e096f96f4f"
|
||||
],
|
||||
"markers": "sys_platform == 'linux'",
|
||||
"version": "==0.7.1"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8",
|
||||
@@ -264,11 +361,11 @@
|
||||
},
|
||||
"keyring": {
|
||||
"hashes": [
|
||||
"sha256:6334aee6073db2fb1f30892697b1730105b5e9a77ce7e61fca6b435225493efe",
|
||||
"sha256:bd2145a237ed70c8ce72978b497619ddfcae640b6dcf494402d5143e37755c6e"
|
||||
"sha256:17e49fb0d6883c2b4445359434dba95aad84aabb29bbff044ad0ed7100232eca",
|
||||
"sha256:89cbd74d4683ed164c8082fb38619341097741323b3786905c6dac04d6915a55"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==23.2.1"
|
||||
"version": "==23.4.1"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
@@ -367,13 +464,20 @@
|
||||
],
|
||||
"version": "==0.4.3"
|
||||
},
|
||||
"nodeenv": {
|
||||
"hashes": [
|
||||
"sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b",
|
||||
"sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"
|
||||
],
|
||||
"version": "==1.6.0"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:096d689d78ca690e4cd8a89568ba06d07ca097e3306a4381635073ca91479966",
|
||||
"sha256:14317396d1e8cdb122989b916fa2c7e9ca8e2be9e8060a6eff75b6b7b4d8a7e0"
|
||||
"sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
|
||||
"sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==21.2"
|
||||
"version": "==21.3"
|
||||
},
|
||||
"parver": {
|
||||
"hashes": [
|
||||
@@ -408,10 +512,10 @@
|
||||
},
|
||||
"pkginfo": {
|
||||
"hashes": [
|
||||
"sha256:37ecd857b47e5f55949c41ed061eb51a0bee97a87c969219d144c0e023982779",
|
||||
"sha256:e7432f81d08adec7297633191bbf0bd47faf13cd8724c3a13250e51d542635bd"
|
||||
"sha256:542e0d0b6750e2e21c20179803e40ab50598d8066d51097a0e382cba9eb02bff",
|
||||
"sha256:c24c487c6a7f72c66e816ab1796b96ac6c3d14d49338293d2141664330b55ffc"
|
||||
],
|
||||
"version": "==1.7.1"
|
||||
"version": "==1.8.2"
|
||||
},
|
||||
"platformdirs": {
|
||||
"hashes": [
|
||||
@@ -429,6 +533,14 @@
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.0.0"
|
||||
},
|
||||
"pre-commit": {
|
||||
"hashes": [
|
||||
"sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616",
|
||||
"sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.17.0"
|
||||
},
|
||||
"py": {
|
||||
"hashes": [
|
||||
"sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719",
|
||||
@@ -445,6 +557,13 @@
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.7.0"
|
||||
},
|
||||
"pycparser": {
|
||||
"hashes": [
|
||||
"sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9",
|
||||
"sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"
|
||||
],
|
||||
"version": "==2.21"
|
||||
},
|
||||
"pyenchant": {
|
||||
"hashes": [
|
||||
"sha256:1cf830c6614362a78aab78d50eaf7c6c93831369c52e1bb64ffae1df0341e637",
|
||||
@@ -465,35 +584,35 @@
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380",
|
||||
"sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"
|
||||
"sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65",
|
||||
"sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==2.10.0"
|
||||
"version": "==2.11.2"
|
||||
},
|
||||
"pyparsing": {
|
||||
"hashes": [
|
||||
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
||||
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
||||
"sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea",
|
||||
"sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.4.7"
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.0.7"
|
||||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89",
|
||||
"sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"
|
||||
"sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db",
|
||||
"sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==6.2.5"
|
||||
"version": "==7.0.1"
|
||||
},
|
||||
"pytest-forked": {
|
||||
"hashes": [
|
||||
"sha256:6aa9ac7e00ad1a539c41bec6d21011332de671e938c7637378ec9710204e37ca",
|
||||
"sha256:dc4147784048e70ef5d437951728825a131b81714b398d5d52f17c7c144d8815"
|
||||
"sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e",
|
||||
"sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==1.3.0"
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.4.0"
|
||||
},
|
||||
"pytest-pypi": {
|
||||
"editable": true,
|
||||
@@ -501,19 +620,19 @@
|
||||
},
|
||||
"pytest-timeout": {
|
||||
"hashes": [
|
||||
"sha256:329bdea323d3e5bea4737070dd85a0d1021dbecb2da5342dc25284fdb929dff0",
|
||||
"sha256:a5ec4eceddb8ea726911848593d668594107e797621e97f93a1d1dbc6fbb9080"
|
||||
"sha256:c07ca07404c612f8abbe22294b23c368e2e5104b521c1790195561f37e1ac3d9",
|
||||
"sha256:f6f50101443ce70ad325ceb4473c4255e9d74e3c7cd0ef827309dfa4c0d975c6"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.1"
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"pytest-xdist": {
|
||||
"hashes": [
|
||||
"sha256:7b61ebb46997a0820a263553179d6d1e25a8c50d8a8620cd1aa1e20e3be99168",
|
||||
"sha256:89b330316f7fc475f999c81b577c2b926c9569f3d397ae432c0c2e2496d61ff9"
|
||||
"sha256:4580deca3ff04ddb2ac53eba39d76cb5dd5edeac050cb6fbc768b0dd712b4edf",
|
||||
"sha256:6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.4.0"
|
||||
"version": "==2.5.0"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
@@ -522,82 +641,60 @@
|
||||
],
|
||||
"version": "==2021.3"
|
||||
},
|
||||
"pywin32-ctypes": {
|
||||
"pyyaml": {
|
||||
"hashes": [
|
||||
"sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942",
|
||||
"sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"
|
||||
"sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293",
|
||||
"sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b",
|
||||
"sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57",
|
||||
"sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b",
|
||||
"sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4",
|
||||
"sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07",
|
||||
"sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba",
|
||||
"sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9",
|
||||
"sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287",
|
||||
"sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513",
|
||||
"sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0",
|
||||
"sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0",
|
||||
"sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92",
|
||||
"sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f",
|
||||
"sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2",
|
||||
"sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc",
|
||||
"sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c",
|
||||
"sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86",
|
||||
"sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4",
|
||||
"sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c",
|
||||
"sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34",
|
||||
"sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b",
|
||||
"sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c",
|
||||
"sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb",
|
||||
"sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737",
|
||||
"sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3",
|
||||
"sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d",
|
||||
"sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53",
|
||||
"sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78",
|
||||
"sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803",
|
||||
"sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a",
|
||||
"sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174",
|
||||
"sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"
|
||||
],
|
||||
"markers": "sys_platform == 'win32'",
|
||||
"version": "==0.2.0"
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==6.0"
|
||||
},
|
||||
"readme-renderer": {
|
||||
"hashes": [
|
||||
"sha256:3286806450d9961d6e3b5f8a59f77e61503799aca5155c8d8d40359b4e1e1adc",
|
||||
"sha256:8299700d7a910c304072a7601eafada6712a5b011a20139417e1b1e9f04645d8"
|
||||
"sha256:262510fe6aae81ed4e94d8b169077f325614c0b1a45916a80442c6576264a9c2",
|
||||
"sha256:dfb4d17f21706d145f7473e0b61ca245ba58e810cf9b2209a48239677f82e5b0"
|
||||
],
|
||||
"version": "==30.0"
|
||||
},
|
||||
"regex": {
|
||||
"hashes": [
|
||||
"sha256:05b7d6d7e64efe309972adab77fc2af8907bb93217ec60aa9fe12a0dad35874f",
|
||||
"sha256:0617383e2fe465732af4509e61648b77cbe3aee68b6ac8c0b6fe934db90be5cc",
|
||||
"sha256:07856afef5ffcc052e7eccf3213317fbb94e4a5cd8177a2caa69c980657b3cb4",
|
||||
"sha256:162abfd74e88001d20cb73ceaffbfe601469923e875caf9118333b1a4aaafdc4",
|
||||
"sha256:2207ae4f64ad3af399e2d30dde66f0b36ae5c3129b52885f1bffc2f05ec505c8",
|
||||
"sha256:30ab804ea73972049b7a2a5c62d97687d69b5a60a67adca07eb73a0ddbc9e29f",
|
||||
"sha256:3b5df18db1fccd66de15aa59c41e4f853b5df7550723d26aa6cb7f40e5d9da5a",
|
||||
"sha256:3c5fb32cc6077abad3bbf0323067636d93307c9fa93e072771cf9a64d1c0f3ef",
|
||||
"sha256:416c5f1a188c91e3eb41e9c8787288e707f7d2ebe66e0a6563af280d9b68478f",
|
||||
"sha256:432bd15d40ed835a51617521d60d0125867f7b88acf653e4ed994a1f8e4995dc",
|
||||
"sha256:4aaa4e0705ef2b73dd8e36eeb4c868f80f8393f5f4d855e94025ce7ad8525f50",
|
||||
"sha256:537ca6a3586931b16a85ac38c08cc48f10fc870a5b25e51794c74df843e9966d",
|
||||
"sha256:53db2c6be8a2710b359bfd3d3aa17ba38f8aa72a82309a12ae99d3c0c3dcd74d",
|
||||
"sha256:5537f71b6d646f7f5f340562ec4c77b6e1c915f8baae822ea0b7e46c1f09b733",
|
||||
"sha256:6650f16365f1924d6014d2ea770bde8555b4a39dc9576abb95e3cd1ff0263b36",
|
||||
"sha256:666abff54e474d28ff42756d94544cdfd42e2ee97065857413b72e8a2d6a6345",
|
||||
"sha256:68a067c11463de2a37157930d8b153005085e42bcb7ad9ca562d77ba7d1404e0",
|
||||
"sha256:780b48456a0f0ba4d390e8b5f7c661fdd218934388cde1a974010a965e200e12",
|
||||
"sha256:788aef3549f1924d5c38263104dae7395bf020a42776d5ec5ea2b0d3d85d6646",
|
||||
"sha256:7ee1227cf08b6716c85504aebc49ac827eb88fcc6e51564f010f11a406c0a667",
|
||||
"sha256:7f301b11b9d214f83ddaf689181051e7f48905568b0c7017c04c06dfd065e244",
|
||||
"sha256:83ee89483672b11f8952b158640d0c0ff02dc43d9cb1b70c1564b49abe92ce29",
|
||||
"sha256:85bfa6a5413be0ee6c5c4a663668a2cad2cbecdee367630d097d7823041bdeec",
|
||||
"sha256:9345b6f7ee578bad8e475129ed40123d265464c4cfead6c261fd60fc9de00bcf",
|
||||
"sha256:93a5051fcf5fad72de73b96f07d30bc29665697fb8ecdfbc474f3452c78adcf4",
|
||||
"sha256:962b9a917dd7ceacbe5cd424556914cb0d636001e393b43dc886ba31d2a1e449",
|
||||
"sha256:98ba568e8ae26beb726aeea2273053c717641933836568c2a0278a84987b2a1a",
|
||||
"sha256:a3feefd5e95871872673b08636f96b61ebef62971eab044f5124fb4dea39919d",
|
||||
"sha256:b43c2b8a330a490daaef5a47ab114935002b13b3f9dc5da56d5322ff218eeadb",
|
||||
"sha256:b483c9d00a565633c87abd0aaf27eb5016de23fed952e054ecc19ce32f6a9e7e",
|
||||
"sha256:ba05430e819e58544e840a68b03b28b6d328aff2e41579037e8bab7653b37d83",
|
||||
"sha256:ca5f18a75e1256ce07494e245cdb146f5a9267d3c702ebf9b65c7f8bd843431e",
|
||||
"sha256:d5ca078bb666c4a9d1287a379fe617a6dccd18c3e8a7e6c7e1eb8974330c626a",
|
||||
"sha256:da1a90c1ddb7531b1d5ff1e171b4ee61f6345119be7351104b67ff413843fe94",
|
||||
"sha256:dba70f30fd81f8ce6d32ddeef37d91c8948e5d5a4c63242d16a2b2df8143aafc",
|
||||
"sha256:dd33eb9bdcfbabab3459c9ee651d94c842bc8a05fabc95edf4ee0c15a072495e",
|
||||
"sha256:e0538c43565ee6e703d3a7c3bdfe4037a5209250e8502c98f20fea6f5fdf2965",
|
||||
"sha256:e1f54b9b4b6c53369f40028d2dd07a8c374583417ee6ec0ea304e710a20f80a0",
|
||||
"sha256:e32d2a2b02ccbef10145df9135751abea1f9f076e67a4e261b05f24b94219e36",
|
||||
"sha256:e71255ba42567d34a13c03968736c5d39bb4a97ce98188fafb27ce981115beec",
|
||||
"sha256:ed2e07c6a26ed4bea91b897ee2b0835c21716d9a469a96c3e878dc5f8c55bb23",
|
||||
"sha256:eef2afb0fd1747f33f1ee3e209bce1ed582d1896b240ccc5e2697e3275f037c7",
|
||||
"sha256:f23222527b307970e383433daec128d769ff778d9b29343fb3496472dc20dabe",
|
||||
"sha256:f341ee2df0999bfdf7a95e448075effe0db212a59387de1a70690e4acb03d4c6",
|
||||
"sha256:f7f325be2804246a75a4f45c72d4ce80d2443ab815063cdf70ee8fb2ca59ee1b",
|
||||
"sha256:f8af619e3be812a2059b212064ea7a640aff0568d972cd1b9e920837469eb3cb",
|
||||
"sha256:fa8c626d6441e2d04b6ee703ef2d1e17608ad44c7cb75258c09dd42bacdfc64b",
|
||||
"sha256:fbb9dc00e39f3e6c0ef48edee202f9520dafb233e8b51b06b8428cfcb92abd30",
|
||||
"sha256:fff55f3ce50a3ff63ec8e2a8d3dd924f1941b250b0aac3d3d42b687eeff07a8e"
|
||||
],
|
||||
"version": "==2021.11.10"
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==34.0"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24",
|
||||
"sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"
|
||||
"sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61",
|
||||
"sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==2.26.0"
|
||||
"version": "==2.27.1"
|
||||
},
|
||||
"requests-toolbelt": {
|
||||
"hashes": [
|
||||
@@ -611,15 +708,24 @@
|
||||
"sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835",
|
||||
"sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==1.5.0"
|
||||
},
|
||||
"secretstorage": {
|
||||
"hashes": [
|
||||
"sha256:422d82c36172d88d6a0ed5afdec956514b189ddbfb72fefab0c8a1cee4eaf71f",
|
||||
"sha256:fd666c51a6bf200643495a04abb261f83229dcb6fd8472ec393df7ffc8b6f195"
|
||||
],
|
||||
"markers": "sys_platform == 'linux'",
|
||||
"version": "==3.3.1"
|
||||
},
|
||||
"setuptools": {
|
||||
"hashes": [
|
||||
"sha256:94ee891f4759150cded601a6beb6b08400413aefd0267b692f3f8c6e0bb238e7",
|
||||
"sha256:fb537610c2dfe77b5896e3ee53dd53fbdd9adc48076c8f28cee3a30fb59a5038"
|
||||
"sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373",
|
||||
"sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==59.1.1"
|
||||
"version": "==59.6.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
@@ -720,6 +826,7 @@
|
||||
"hashes": [
|
||||
"sha256:08c22c9c03b28a140fe3ec5064b53a5288279f22e596ca06b0be698d50c93cf2"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "sys_platform == 'linux'",
|
||||
"version": "==0.10.0"
|
||||
},
|
||||
@@ -733,83 +840,88 @@
|
||||
},
|
||||
"tomli": {
|
||||
"hashes": [
|
||||
"sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee",
|
||||
"sha256:f04066f68f5554911363063a30b108d2b5a5b1a010aa8b6132af78489fe3aade"
|
||||
"sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f",
|
||||
"sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.2.2"
|
||||
"version": "==1.2.3"
|
||||
},
|
||||
"towncrier": {
|
||||
"hashes": [
|
||||
"sha256:930454ab86da25aae01bf0f37927e565d9366b12b948d5f533c7c7641dba7b16",
|
||||
"sha256:bfc86ad9dd28c53dfefbb6d7d33875a8f459c5491e18857be4bcff096b3192c3"
|
||||
"sha256:9cb6f45c16e1a1eec9d0e7651165e7be60cd0ab81d13a5c96ca97a498ae87f48",
|
||||
"sha256:fc5a88a2a54988e3a8ed2b60d553599da8330f65722cc607c839614ed87e0f92"
|
||||
],
|
||||
"version": "==21.9.0rc1"
|
||||
"version": "==21.9.0"
|
||||
},
|
||||
"tqdm": {
|
||||
"hashes": [
|
||||
"sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c",
|
||||
"sha256:d359de7217506c9851b7869f3708d8ee53ed70a1b8edbba4dbcb47442592920d"
|
||||
"sha256:1d9835ede8e394bb8c9dcbffbca02d717217113adc679236873eeaac5bc0b3cd",
|
||||
"sha256:e643e071046f17139dea55b880dc9b33822ce21613b4a4f5ea57f202833dbc29"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==4.62.3"
|
||||
"version": "==4.63.0"
|
||||
},
|
||||
"twine": {
|
||||
"hashes": [
|
||||
"sha256:4caad5ef4722e127b3749052fcbffaaf71719b19d4fd4973b29c469957adeba2",
|
||||
"sha256:916070f8ecbd1985ebed5dbb02b9bda9a092882a96d7069d542d4fc0bb5c673c"
|
||||
"sha256:8efa52658e0ae770686a13b675569328f1fba9837e5de1867bfe5f46a9aefe19",
|
||||
"sha256:d0550fca9dc19f3d5e8eadfce0c227294df0a2a951251a4385797c8a6198b7c8"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.6.0"
|
||||
"version": "==3.8.0"
|
||||
},
|
||||
"typed-ast": {
|
||||
"hashes": [
|
||||
"sha256:14fed8820114a389a2b7e91624db5f85f3f6682fda09fe0268a59aabd28fe5f5",
|
||||
"sha256:155b74b078be842d2eb630dd30a280025eca0a5383c7d45853c27afee65f278f",
|
||||
"sha256:224afecb8b39739f5c9562794a7c98325cb9d972712e1a98b6989a4720219541",
|
||||
"sha256:361b9e5d27bd8e3ccb6ea6ad6c4f3c0be322a1a0f8177db6d56264fa0ae40410",
|
||||
"sha256:37ba2ab65a0028b1a4f2b61a8fe77f12d242731977d274a03d68ebb751271508",
|
||||
"sha256:49af5b8f6f03ed1eb89ee06c1d7c2e7c8e743d720c3746a5857609a1abc94c94",
|
||||
"sha256:51040bf45aacefa44fa67fb9ebcd1f2bec73182b99a532c2394eea7dabd18e24",
|
||||
"sha256:52ca2b2b524d770bed7a393371a38e91943f9160a190141e0df911586066ecda",
|
||||
"sha256:618912cbc7e17b4aeba86ffe071698c6e2d292acbd6d1d5ec1ee724b8c4ae450",
|
||||
"sha256:65c81abbabda7d760df7304d843cc9dbe7ef5d485504ca59a46ae2d1731d2428",
|
||||
"sha256:7b310a207ee9fde3f46ba327989e6cba4195bc0c8c70a158456e7b10233e6bed",
|
||||
"sha256:7e6731044f748340ef68dcadb5172a4b1f40847a2983fe3983b2a66445fbc8e6",
|
||||
"sha256:806e0c7346b9b4af8c62d9a29053f484599921a4448c37fbbcbbf15c25138570",
|
||||
"sha256:a67fd5914603e2165e075f1b12f5a8356bfb9557e8bfb74511108cfbab0f51ed",
|
||||
"sha256:e4374a76e61399a173137e7984a1d7e356038cf844f24fd8aea46c8029a2f712",
|
||||
"sha256:e8a9b9c87801cecaad3b4c2b8876387115d1a14caa602c1618cedbb0cb2a14e6",
|
||||
"sha256:ea517c2bb11c5e4ba7a83a91482a2837041181d57d3ed0749a6c382a2b6b7086",
|
||||
"sha256:ec184dfb5d3d11e82841dbb973e7092b75f306b625fad7b2e665b64c5d60ab3f",
|
||||
"sha256:ff4ad88271aa7a55f19b6a161ed44e088c393846d954729549e3cde8257747bb"
|
||||
"sha256:0eb77764ea470f14fcbb89d51bc6bbf5e7623446ac4ed06cbd9ca9495b62e36e",
|
||||
"sha256:1098df9a0592dd4c8c0ccfc2e98931278a6c6c53cb3a3e2cf7e9ee3b06153344",
|
||||
"sha256:183b183b7771a508395d2cbffd6db67d6ad52958a5fdc99f450d954003900266",
|
||||
"sha256:18fe320f354d6f9ad3147859b6e16649a0781425268c4dde596093177660e71a",
|
||||
"sha256:26a432dc219c6b6f38be20a958cbe1abffcc5492821d7e27f08606ef99e0dffd",
|
||||
"sha256:294a6903a4d087db805a7656989f613371915fc45c8cc0ddc5c5a0a8ad9bea4d",
|
||||
"sha256:31d8c6b2df19a777bc8826770b872a45a1f30cfefcfd729491baa5237faae837",
|
||||
"sha256:33b4a19ddc9fc551ebabca9765d54d04600c4a50eda13893dadf67ed81d9a098",
|
||||
"sha256:42c47c3b43fe3a39ddf8de1d40dbbfca60ac8530a36c9b198ea5b9efac75c09e",
|
||||
"sha256:525a2d4088e70a9f75b08b3f87a51acc9cde640e19cc523c7e41aa355564ae27",
|
||||
"sha256:58ae097a325e9bb7a684572d20eb3e1809802c5c9ec7108e85da1eb6c1a3331b",
|
||||
"sha256:676d051b1da67a852c0447621fdd11c4e104827417bf216092ec3e286f7da596",
|
||||
"sha256:74cac86cc586db8dfda0ce65d8bcd2bf17b58668dfcc3652762f3ef0e6677e76",
|
||||
"sha256:8c08d6625bb258179b6e512f55ad20f9dfef019bbfbe3095247401e053a3ea30",
|
||||
"sha256:90904d889ab8e81a956f2c0935a523cc4e077c7847a836abee832f868d5c26a4",
|
||||
"sha256:963a0ccc9a4188524e6e6d39b12c9ca24cc2d45a71cfdd04a26d883c922b4b78",
|
||||
"sha256:bbebc31bf11762b63bf61aaae232becb41c5bf6b3461b80a4df7e791fabb3aca",
|
||||
"sha256:bc2542e83ac8399752bc16e0b35e038bdb659ba237f4222616b4e83fb9654985",
|
||||
"sha256:c29dd9a3a9d259c9fa19d19738d021632d673f6ed9b35a739f48e5f807f264fb",
|
||||
"sha256:c7407cfcad702f0b6c0e0f3e7ab876cd1d2c13b14ce770e412c0c4b9728a0f88",
|
||||
"sha256:da0a98d458010bf4fe535f2d1e367a2e2060e105978873c04c04212fb20543f7",
|
||||
"sha256:df05aa5b241e2e8045f5f4367a9f6187b09c4cdf8578bb219861c4e27c443db5",
|
||||
"sha256:f290617f74a610849bd8f5514e34ae3d09eafd521dceaa6cf68b3f4414266d4e",
|
||||
"sha256:f30ddd110634c2d7534b2d4e0e22967e88366b0d356b24de87419cc4410c41b7"
|
||||
],
|
||||
"markers": "python_version < '3.8' and implementation_name == 'cpython'",
|
||||
"version": "==1.5.0"
|
||||
"version": "==1.5.2"
|
||||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
"sha256:2cdf80e4e04866a9b3689a51869016d36db0814d84b8d8a568d22781d45d27ed",
|
||||
"sha256:829704698b22e13ec9eaf959122315eabb370b0884400e9818334d8b677023d9"
|
||||
"sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42",
|
||||
"sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==4.0.0"
|
||||
"version": "==4.1.1"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece",
|
||||
"sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"
|
||||
"sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
|
||||
"sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
|
||||
"version": "==1.26.7"
|
||||
"version": "==1.26.9"
|
||||
},
|
||||
"virtualenv": {
|
||||
"hashes": [
|
||||
"sha256:4b02e52a624336eece99c96e3ab7111f469c24ba226a53ec474e8e787b365814",
|
||||
"sha256:576d05b46eace16a9c348085f7d0dc8ef28713a2cabaa1cf0aea41e8f12c9218"
|
||||
"sha256:c3e01300fb8495bc00ed70741f5271fc95fed067eb7106297be73d30879af60c",
|
||||
"sha256:ce8901d3bbf3b90393498187f2d56797a8a452fb2d0d7efc6fd837554d6f679c"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==20.10.0"
|
||||
"version": "==20.13.4"
|
||||
},
|
||||
"virtualenv-clone": {
|
||||
"hashes": [
|
||||
@@ -828,18 +940,18 @@
|
||||
},
|
||||
"werkzeug": {
|
||||
"hashes": [
|
||||
"sha256:63d3dc1cf60e7b7e35e97fa9861f7397283b75d765afcaefd993d6046899de8f",
|
||||
"sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a"
|
||||
"sha256:1421ebfc7648a39a5c58c601b154165d05cf47a3cd0ccb70857cbdacf6c8f2b8",
|
||||
"sha256:b863f8ff057c522164b6067c9e28b041161b4be5ba4d0daceeaa50a163822d3c"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.2"
|
||||
"version": "==2.0.3"
|
||||
},
|
||||
"zipp": {
|
||||
"hashes": [
|
||||
"sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832",
|
||||
"sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"markers": "python_version < '3.10'",
|
||||
"version": "==3.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -274,7 +274,7 @@ Example::
|
||||
|
||||
.. note::
|
||||
|
||||
Each month, `PyUp.io` updates the ``safety`` database of
|
||||
Each month, `PyUp.io`_ updates the ``safety`` database of
|
||||
insecure Python packages and `makes it available to the
|
||||
community for free <https://pyup.io/safety/>`__. Pipenv
|
||||
makes an API call to retrieve those results and use them
|
||||
@@ -380,7 +380,7 @@ If a ``.env`` file is present in your project, ``$ pipenv shell`` and ``$ pipenv
|
||||
>>> os.environ['HELLO']
|
||||
'WORLD'
|
||||
|
||||
Shell like variable expansion is available in ``.env`` files using `${VARNAME}` syntax.::
|
||||
Shell like variable expansion is available in ``.env`` files using ``${VARNAME}`` syntax.::
|
||||
|
||||
$ cat .env
|
||||
CONFIG_PATH=${HOME}/.config/foo
|
||||
@@ -591,15 +591,15 @@ Magic shell completions are now enabled!
|
||||
It's reasonably common for platform specific Python bindings for
|
||||
operating system interfaces to only be available through the system
|
||||
package manager, and hence unavailable for installation into virtual
|
||||
environments with `pip`. In these cases, the virtual environment can
|
||||
be created with access to the system `site-packages` directory::
|
||||
environments with ``pip``. In these cases, the virtual environment can
|
||||
be created with access to the system ``site-packages`` directory::
|
||||
|
||||
$ pipenv --three --site-packages
|
||||
|
||||
To ensure that all `pip`-installable components actually are installed
|
||||
To ensure that all ``pip``-installable components actually are installed
|
||||
into the virtual environment and system packages are only used for
|
||||
interfaces that don't participate in Python-level dependency resolution
|
||||
at all, use the `PIP_IGNORE_INSTALLED` setting::
|
||||
at all, use the ``PIP_IGNORE_INSTALLED`` setting::
|
||||
|
||||
$ PIP_IGNORE_INSTALLED=1 pipenv install --dev
|
||||
|
||||
@@ -618,7 +618,7 @@ Libraries are ultimately meant to be used in some **application**. Applications
|
||||
To summarize:
|
||||
|
||||
- For libraries, define **abstract dependencies** via ``install_requires`` in ``setup.py``. The decision of which version exactly to be installed and where to obtain that dependency is not yours to make!
|
||||
- For applications, define **dependencies and where to get them** in the `Pipfile` and use this file to update the set of **concrete dependencies** in ``Pipfile.lock``. This file defines a specific idempotent environment that is known to work for your project. The ``Pipfile.lock`` is your source of truth. The ``Pipfile`` is a convenience for you to create that lock-file, in that it allows you to still remain somewhat vague about the exact version of a dependency to be used. Pipenv is there to help you define a working conflict-free set of specific dependency-versions, which would otherwise be a very tedious task.
|
||||
- For applications, define **dependencies and where to get them** in the ``Pipfile`` and use this file to update the set of **concrete dependencies** in ``Pipfile.lock``. This file defines a specific idempotent environment that is known to work for your project. The ``Pipfile.lock`` is your source of truth. The ``Pipfile`` is a convenience for you to create that lock-file, in that it allows you to still remain somewhat vague about the exact version of a dependency to be used. Pipenv is there to help you define a working conflict-free set of specific dependency-versions, which would otherwise be a very tedious task.
|
||||
- Of course, ``Pipfile`` and Pipenv are still useful for library developers, as they can be used to define a development or test environment.
|
||||
- And, of course, there are projects for which the distinction between library and application isn't that clear. In that case, use ``install_requires`` alongside Pipenv and ``Pipfile``.
|
||||
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@ Example Pipfile.lock
|
||||
|
||||
- Generally, keep both ``Pipfile`` and ``Pipfile.lock`` in version control.
|
||||
- Do not keep ``Pipfile.lock`` in version control if multiple versions of Python are being targeted.
|
||||
- Specify your target Python version in your `Pipfile`'s ``[requires]`` section. Ideally, you should only have one target Python version, as this is a deployment tool. ``python_version`` should be in the format ``X.Y`` (or ``X``) and ``python_full_version`` should be in ``X.Y.Z`` format.
|
||||
- Specify your target Python version in your ``Pipfile``'s ``[requires]`` section. Ideally, you should only have one target Python version, as this is a deployment tool. ``python_version`` should be in the format ``X.Y`` (or ``X``) and ``python_full_version`` should be in ``X.Y.Z`` format.
|
||||
- ``pipenv install`` is fully compatible with ``pip install`` syntax, for which the full documentation can be found `here <https://pip.pypa.io/en/stable/user_guide/#installing-packages>`_.
|
||||
- Note that the ``Pipfile`` uses the `TOML Spec <https://github.com/toml-lang/toml#user-content-spec>`_.
|
||||
|
||||
|
||||
+44
-40
@@ -34,38 +34,38 @@ with open(os.path.join(here, "..", "pipenv", "__version__.py")) as f:
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx_click.ext',
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.todo",
|
||||
"sphinx.ext.coverage",
|
||||
"sphinx.ext.viewcode",
|
||||
"sphinx_click.ext",
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
templates_path = ["_templates"]
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
source_suffix = ".rst"
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
master_doc = "index"
|
||||
|
||||
# General information about the project.
|
||||
project = 'pipenv'
|
||||
project = "pipenv"
|
||||
copyright = '2020. A project founded by <a href="http://kennethreitz.com/pages/open-projects.html">Kenneth Reitz</a>'
|
||||
author = 'Python Packaging Authority'
|
||||
author = "Python Packaging Authority"
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = about['__version__']
|
||||
version = about["__version__"]
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = about['__version__']
|
||||
release = about["__version__"]
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@@ -77,10 +77,10 @@ language = None
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
pygments_style = "sphinx"
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
@@ -90,42 +90,47 @@ todo_include_todos = True
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'alabaster'
|
||||
html_theme = "alabaster"
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
html_theme_options = {
|
||||
'show_powered_by': False,
|
||||
'github_user': 'pypa',
|
||||
'github_repo': 'pipenv',
|
||||
'github_banner': False,
|
||||
'show_related': False
|
||||
"show_powered_by": False,
|
||||
"github_user": "pypa",
|
||||
"github_repo": "pipenv",
|
||||
"github_banner": False,
|
||||
"show_related": False,
|
||||
}
|
||||
|
||||
html_sidebars = {
|
||||
'index': ['sidebarintro.html', 'sourcelink.html', 'searchbox.html',
|
||||
'hacks.html'],
|
||||
'**': ['sidebarlogo.html', 'localtoc.html', 'relations.html',
|
||||
'sourcelink.html', 'searchbox.html', 'hacks.html']
|
||||
"index": ["sidebarintro.html", "sourcelink.html", "searchbox.html", "hacks.html"],
|
||||
"**": [
|
||||
"sidebarlogo.html",
|
||||
"localtoc.html",
|
||||
"relations.html",
|
||||
"sourcelink.html",
|
||||
"searchbox.html",
|
||||
"hacks.html",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
html_static_path = ["_static"]
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.add_stylesheet('custom.css')
|
||||
app.add_stylesheet("custom.css")
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'pipenvdoc'
|
||||
htmlhelp_basename = "pipenvdoc"
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
@@ -134,15 +139,12 @@ latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
@@ -152,8 +154,7 @@ latex_elements = {
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'pipenv.tex', 'pipenv Documentation',
|
||||
'Kenneth Reitz', 'manual'),
|
||||
(master_doc, "pipenv.tex", "pipenv Documentation", "Kenneth Reitz", "manual"),
|
||||
]
|
||||
|
||||
|
||||
@@ -161,10 +162,7 @@ latex_documents = [
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'pipenv', 'pipenv Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
man_pages = [(master_doc, "pipenv", "pipenv Documentation", [author], 1)]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
@@ -173,9 +171,15 @@ man_pages = [
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'pipenv', 'pipenv Documentation',
|
||||
author, 'pipenv', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
(
|
||||
master_doc,
|
||||
"pipenv",
|
||||
"pipenv Documentation",
|
||||
author,
|
||||
"pipenv",
|
||||
"One line description of project.",
|
||||
"Miscellaneous",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -197,4 +201,4 @@ epub_copyright = copyright
|
||||
# epub_uid = ''
|
||||
|
||||
# A list of files that should not be packed into the epub file.
|
||||
epub_exclude_files = ['search.html']
|
||||
epub_exclude_files = ["search.html"]
|
||||
|
||||
@@ -106,6 +106,18 @@ See `pypa/pipenv#2557`_ for more details.
|
||||
|
||||
.. _pypa/pipenv#2557: https://github.com/pypa/pipenv/issues/2557
|
||||
|
||||
Pipenv now uses pre-commit hooks similar to Pip in order to apply linting and
|
||||
code formatting automatically! The build now also checks that these linting rules
|
||||
have been applied to the code before running the tests.
|
||||
The build will fail when linting changes are detected so be sure to sync dev requirements
|
||||
and install the pre-commit hooks locally:
|
||||
|
||||
$ ``pipenv install --dev``
|
||||
# This will configure running the pre-commit checks at start of each commit
|
||||
$ ``pre-commit install``
|
||||
# Should you want to check the pre-commit configuration against all configured project files
|
||||
$ ``pre-commit run --all-files --verbose``
|
||||
|
||||
|
||||
.. _testing:
|
||||
|
||||
@@ -272,10 +284,11 @@ It is important that your environment is setup correctly, and
|
||||
this may take some work, for example, on a specific Mac installation, the following
|
||||
steps may be needed::
|
||||
|
||||
.. code-block:: bash
|
||||
# Make sure the tests can access github
|
||||
if [ "$SSH_AGENT_PID" = "" ]
|
||||
then
|
||||
eval `ssh-agent`
|
||||
eval ``ssh-agent``
|
||||
ssh-add
|
||||
fi
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
.. pipenv documentation master file, created by
|
||||
sphinx-quickstart on Mon Jan 30 13:28:36 2017.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
contain the root ``toctree`` directive.
|
||||
|
||||
Pipenv: Python Dev Workflow for Humans
|
||||
======================================
|
||||
|
||||
@@ -108,12 +108,14 @@ def determine_pip_install_arguments():
|
||||
if implicit_setuptools:
|
||||
try:
|
||||
import setuptools # noqa
|
||||
|
||||
implicit_setuptools = False
|
||||
except ImportError:
|
||||
pass
|
||||
if implicit_wheel:
|
||||
try:
|
||||
import wheel # noqa
|
||||
|
||||
implicit_wheel = False
|
||||
except ImportError:
|
||||
pass
|
||||
@@ -164,6 +166,7 @@ def bootstrap(tmpdir):
|
||||
# Execute the included pip and use it to install the latest pip and
|
||||
# setuptools from PyPI
|
||||
from pip._internal.cli.main import main as pip_entry_point
|
||||
|
||||
args = determine_pip_install_arguments()
|
||||
sys.exit(pip_entry_point(args))
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Internal to pipenv, the utils.py was split into a utils module with unused code removed.
|
||||
@@ -0,0 +1,2 @@
|
||||
Added code linting using pre-commit-hooks, black, flake8, isort, pygrep-hooks, news-fragments and check-manifest.
|
||||
Very similar to pip's configuration; adds a towncrier new's type ``process`` for change to Development processes.
|
||||
+1
-2
@@ -9,7 +9,6 @@ import warnings
|
||||
|
||||
from pipenv.__version__ import __version__ # noqa
|
||||
|
||||
|
||||
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"])
|
||||
@@ -54,8 +53,8 @@ if os.name == "nt":
|
||||
sys.stdout = stdout
|
||||
sys.stderr = stderr
|
||||
|
||||
from .cli import cli
|
||||
from . import resolver # noqa
|
||||
from .cli import cli
|
||||
|
||||
if __name__ == "__main__":
|
||||
cli()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from pipenv.cli import cli
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
cli()
|
||||
|
||||
+10
-3
@@ -12,13 +12,19 @@ warnings.filterwarnings("ignore", category=ResourceWarning)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"getpreferredencoding", "DEFAULT_ENCODING", "canonical_encoding_name",
|
||||
"force_encoding", "UNICODE_TO_ASCII_TRANSLATION_MAP", "decode_output", "fix_utf8"
|
||||
"getpreferredencoding",
|
||||
"DEFAULT_ENCODING",
|
||||
"canonical_encoding_name",
|
||||
"force_encoding",
|
||||
"UNICODE_TO_ASCII_TRANSLATION_MAP",
|
||||
"decode_output",
|
||||
"fix_utf8",
|
||||
]
|
||||
|
||||
|
||||
def getpreferredencoding():
|
||||
import locale
|
||||
|
||||
# Borrowed from Invoke
|
||||
# (see https://github.com/pyinvoke/invoke/blob/93af29d/invoke/runners.py#L881)
|
||||
return locale.getpreferredencoding(False)
|
||||
@@ -29,6 +35,7 @@ DEFAULT_ENCODING = getpreferredencoding()
|
||||
|
||||
def canonical_encoding_name(name):
|
||||
import codecs
|
||||
|
||||
try:
|
||||
codec = codecs.lookup(name)
|
||||
except LookupError:
|
||||
@@ -55,7 +62,7 @@ def force_encoding():
|
||||
if stdout_encoding != "utf-8" or stderr_encoding != "utf-8":
|
||||
|
||||
try:
|
||||
from ctypes import pythonapi, py_object, c_char_p
|
||||
from ctypes import c_char_p, py_object, pythonapi
|
||||
except ImportError:
|
||||
return DEFAULT_ENCODING, DEFAULT_ENCODING
|
||||
try:
|
||||
|
||||
+120
-83
@@ -5,25 +5,41 @@ from pipenv import environments
|
||||
from pipenv.__version__ import __version__
|
||||
from pipenv._compat import fix_utf8
|
||||
from pipenv.cli.options import (
|
||||
CONTEXT_SETTINGS, PipenvGroup, common_options, deploy_option,
|
||||
general_options, install_options, lock_options, pass_state,
|
||||
pypi_mirror_option, python_option, site_packages_option, skip_lock_option,
|
||||
sync_options, system_option, three_option, uninstall_options, verbose_option
|
||||
CONTEXT_SETTINGS,
|
||||
PipenvGroup,
|
||||
common_options,
|
||||
deploy_option,
|
||||
general_options,
|
||||
install_options,
|
||||
lock_options,
|
||||
pass_state,
|
||||
pypi_mirror_option,
|
||||
python_option,
|
||||
site_packages_option,
|
||||
skip_lock_option,
|
||||
sync_options,
|
||||
system_option,
|
||||
three_option,
|
||||
uninstall_options,
|
||||
verbose_option,
|
||||
)
|
||||
from pipenv.exceptions import PipenvOptionsError
|
||||
from pipenv.patched import crayons
|
||||
from pipenv.utils.processes import subprocess_run
|
||||
from pipenv.vendor.click import (
|
||||
Choice, argument, echo, edit, group, option, pass_context, secho, types,
|
||||
version_option
|
||||
Choice,
|
||||
argument,
|
||||
echo,
|
||||
edit,
|
||||
group,
|
||||
option,
|
||||
pass_context,
|
||||
secho,
|
||||
version_option,
|
||||
)
|
||||
|
||||
|
||||
subcommand_context = CONTEXT_SETTINGS.copy()
|
||||
subcommand_context.update({
|
||||
"ignore_unknown_options": True,
|
||||
"allow_extra_args": True
|
||||
})
|
||||
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
|
||||
|
||||
@@ -31,8 +47,12 @@ 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("--man", is_flag=True, default=False, help="Display manpage.")
|
||||
@@ -58,21 +78,33 @@ def cli(
|
||||
support=None,
|
||||
help=False,
|
||||
site_packages=None,
|
||||
**kwargs
|
||||
**kwargs,
|
||||
):
|
||||
from ..core import (
|
||||
cleanup_virtualenv, do_clear, do_py, do_where, ensure_project,
|
||||
format_help, system_which, warn_in_virtualenv
|
||||
)
|
||||
from pipenv.utils.spinner import create_spinner
|
||||
|
||||
from ..core import (
|
||||
cleanup_virtualenv,
|
||||
do_clear,
|
||||
do_py,
|
||||
do_where,
|
||||
ensure_project,
|
||||
format_help,
|
||||
system_which,
|
||||
warn_in_virtualenv,
|
||||
)
|
||||
|
||||
if man:
|
||||
if system_which("man"):
|
||||
path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "pipenv.1")
|
||||
os.execle(system_which("man"), "man", path, os.environ)
|
||||
return 0
|
||||
else:
|
||||
secho("man does not appear to be available on your system.", fg="yellow", bold=True, err=True)
|
||||
secho(
|
||||
"man does not appear to be available on your system.",
|
||||
fg="yellow",
|
||||
bold=True,
|
||||
err=True,
|
||||
)
|
||||
return 1
|
||||
if envs:
|
||||
echo("The following environment variables can be set, to do various things:\n")
|
||||
@@ -114,7 +146,7 @@ def cli(
|
||||
"{}({}){}".format(
|
||||
crayons.red("No virtualenv has been created for this project"),
|
||||
crayons.normal(state.project.project_directory, bold=True),
|
||||
crayons.red(" yet!")
|
||||
crayons.red(" yet!"),
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
@@ -183,10 +215,7 @@ def cli(
|
||||
@skip_lock_option
|
||||
@install_options
|
||||
@pass_state
|
||||
def install(
|
||||
state,
|
||||
**kwargs
|
||||
):
|
||||
def install(state, **kwargs):
|
||||
"""Installs provided packages and adds them to Pipfile, or (if no packages are given), installs all packages from Pipfile."""
|
||||
from ..core import do_install
|
||||
|
||||
@@ -210,13 +239,13 @@ def install(
|
||||
extra_index_url=state.extra_index_urls,
|
||||
packages=state.installstate.packages,
|
||||
editable_packages=state.installstate.editables,
|
||||
site_packages=state.site_packages
|
||||
site_packages=state.site_packages,
|
||||
)
|
||||
|
||||
|
||||
@cli.command(
|
||||
short_help="Uninstalls a provided package and removes it from Pipfile.",
|
||||
context_settings=subcommand_context
|
||||
context_settings=subcommand_context,
|
||||
)
|
||||
@option(
|
||||
"--all-dev",
|
||||
@@ -233,15 +262,10 @@ def install(
|
||||
@uninstall_options
|
||||
@pass_state
|
||||
@pass_context
|
||||
def uninstall(
|
||||
ctx,
|
||||
state,
|
||||
all_dev=False,
|
||||
all=False,
|
||||
**kwargs
|
||||
):
|
||||
def uninstall(ctx, state, all_dev=False, all=False, **kwargs):
|
||||
"""Uninstalls a provided package and removes it from Pipfile."""
|
||||
from ..core import do_uninstall
|
||||
|
||||
retcode = do_uninstall(
|
||||
state.project,
|
||||
packages=state.installstate.packages,
|
||||
@@ -254,7 +278,7 @@ def uninstall(
|
||||
all=all,
|
||||
keep_outdated=state.installstate.keep_outdated,
|
||||
pypi_mirror=state.pypi_mirror,
|
||||
ctx=ctx
|
||||
ctx=ctx,
|
||||
)
|
||||
if retcode:
|
||||
sys.exit(retcode)
|
||||
@@ -280,11 +304,7 @@ LOCK_DEV_NOTE = """\
|
||||
@lock_options
|
||||
@pass_state
|
||||
@pass_context
|
||||
def lock(
|
||||
ctx,
|
||||
state,
|
||||
**kwargs
|
||||
):
|
||||
def lock(ctx, state, **kwargs):
|
||||
"""Generates Pipfile.lock."""
|
||||
from ..core import do_init, do_lock, ensure_project
|
||||
|
||||
@@ -292,8 +312,12 @@ def lock(
|
||||
# Note that we don't pass clear on to ensure_project as it is also
|
||||
# handled in do_lock
|
||||
ensure_project(
|
||||
state.project, three=state.three, python=state.python, pypi_mirror=state.pypi_mirror,
|
||||
warn=(not state.quiet), site_packages=state.site_packages,
|
||||
state.project,
|
||||
three=state.three,
|
||||
python=state.python,
|
||||
pypi_mirror=state.pypi_mirror,
|
||||
warn=(not state.quiet),
|
||||
site_packages=state.site_packages,
|
||||
)
|
||||
emit_requirements = state.lockoptions.emit_requirements
|
||||
dev = state.installstate.dev
|
||||
@@ -325,7 +349,7 @@ def lock(
|
||||
raise PipenvOptionsError(
|
||||
"--dev-only",
|
||||
"--dev-only is only permitted in combination with --requirements. "
|
||||
"Aborting."
|
||||
"Aborting.",
|
||||
)
|
||||
do_lock(
|
||||
state.project,
|
||||
@@ -409,6 +433,7 @@ def shell(
|
||||
def run(state, command, args):
|
||||
"""Spawns a command installed into the virtualenv."""
|
||||
from ..core import do_run
|
||||
|
||||
do_run(
|
||||
state.project,
|
||||
command=command,
|
||||
@@ -416,19 +441,19 @@ def run(state, command, args):
|
||||
three=state.three,
|
||||
python=state.python,
|
||||
pypi_mirror=state.pypi_mirror,
|
||||
quiet=state.quiet
|
||||
quiet=state.quiet,
|
||||
)
|
||||
|
||||
|
||||
@cli.command(
|
||||
short_help="Checks for PyUp Safety security vulnerabilities and against"
|
||||
" PEP 508 markers provided in Pipfile.",
|
||||
context_settings=subcommand_context
|
||||
context_settings=subcommand_context,
|
||||
)
|
||||
@option(
|
||||
"--db",
|
||||
nargs=1,
|
||||
default=lambda: os.environ.get('PIPENV_SAFETY_DB'),
|
||||
default=lambda: os.environ.get("PIPENV_SAFETY_DB"),
|
||||
help="Path to a local PyUp Safety vulnerabilities database."
|
||||
" Default: ENV PIPENV_SAFETY_DB or None.",
|
||||
)
|
||||
@@ -450,6 +475,9 @@ def run(state, command, args):
|
||||
" vulnerabilities database. Leave blank for scanning against a"
|
||||
" database that only updates once a month.",
|
||||
)
|
||||
@option(
|
||||
"--quiet", is_flag=True, help="Quiet standard output, except vulnerability report."
|
||||
)
|
||||
@common_options
|
||||
@system_option
|
||||
@pass_state
|
||||
@@ -461,7 +489,7 @@ def check(
|
||||
output="default",
|
||||
key=None,
|
||||
quiet=False,
|
||||
**kwargs
|
||||
**kwargs,
|
||||
):
|
||||
"""Checks for PyUp Safety security vulnerabilities and against PEP 508 markers provided in Pipfile."""
|
||||
from ..core import do_check
|
||||
@@ -482,31 +510,33 @@ def check(
|
||||
|
||||
@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="List out-of-date dependencies."
|
||||
)
|
||||
@option("--outdated", is_flag=True, default=False, help="List out-of-date dependencies.")
|
||||
@option("--dry-run", is_flag=True, default=None, help="List out-of-date dependencies.")
|
||||
@install_options
|
||||
@pass_state
|
||||
@pass_context
|
||||
def update(
|
||||
ctx,
|
||||
state,
|
||||
bare=False,
|
||||
dry_run=None,
|
||||
outdated=False,
|
||||
**kwargs
|
||||
):
|
||||
def update(ctx, state, bare=False, dry_run=None, outdated=False, **kwargs):
|
||||
"""Runs lock, then sync."""
|
||||
from ..core import do_lock, do_outdated, do_sync, ensure_project
|
||||
|
||||
ensure_project(
|
||||
state.project, three=state.three, python=state.python, pypi_mirror=state.pypi_mirror,
|
||||
warn=(not state.quiet), site_packages=state.site_packages, clear=state.clear
|
||||
state.project,
|
||||
three=state.three,
|
||||
python=state.python,
|
||||
pypi_mirror=state.pypi_mirror,
|
||||
warn=(not state.quiet),
|
||||
site_packages=state.site_packages,
|
||||
clear=state.clear,
|
||||
)
|
||||
if not outdated:
|
||||
outdated = bool(dry_run)
|
||||
if outdated:
|
||||
do_outdated(state.project, clear=state.clear, pre=state.installstate.pre, pypi_mirror=state.pypi_mirror)
|
||||
do_outdated(
|
||||
state.project,
|
||||
clear=state.clear,
|
||||
pre=state.installstate.pre,
|
||||
pypi_mirror=state.pypi_mirror,
|
||||
)
|
||||
packages = [p for p in state.installstate.packages if p]
|
||||
editable = [p for p in state.installstate.editables if p]
|
||||
if not packages:
|
||||
@@ -557,7 +587,7 @@ def update(
|
||||
|
||||
@cli.command(
|
||||
short_help="Displays currently-installed dependency graph information.",
|
||||
context_settings=CONTEXT_SETTINGS
|
||||
context_settings=CONTEXT_SETTINGS,
|
||||
)
|
||||
@option("--bare", is_flag=True, default=False, help="Minimal output.")
|
||||
@option("--json", is_flag=True, default=False, help="Output JSON.")
|
||||
@@ -572,8 +602,9 @@ def graph(state, bare=False, json=False, json_tree=False, reverse=False):
|
||||
|
||||
|
||||
@cli.command(
|
||||
short_help="View a given module in your editor.", name="open",
|
||||
context_settings=CONTEXT_SETTINGS
|
||||
short_help="View a given module in your editor.",
|
||||
name="open",
|
||||
context_settings=CONTEXT_SETTINGS,
|
||||
)
|
||||
@common_options
|
||||
@argument("module", nargs=1)
|
||||
@@ -590,11 +621,18 @@ def run_open(state, module, *args, **kwargs):
|
||||
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(
|
||||
state.project, three=state.three, python=state.python,
|
||||
validate=False, pypi_mirror=state.pypi_mirror,
|
||||
state.project,
|
||||
three=state.three,
|
||||
python=state.python,
|
||||
validate=False,
|
||||
pypi_mirror=state.pypi_mirror,
|
||||
)
|
||||
c = subprocess_run(
|
||||
[state.project._which("python"), "-c", "import {0}; print({0}.__file__)".format(module)]
|
||||
[
|
||||
state.project._which("python"),
|
||||
"-c",
|
||||
"import {0}; print({0}.__file__)".format(module),
|
||||
]
|
||||
)
|
||||
if c.returncode:
|
||||
echo(crayons.red("Module not found!"))
|
||||
@@ -611,21 +649,14 @@ def run_open(state, module, *args, **kwargs):
|
||||
|
||||
@cli.command(
|
||||
short_help="Installs all packages specified in Pipfile.lock.",
|
||||
context_settings=CONTEXT_SETTINGS
|
||||
context_settings=CONTEXT_SETTINGS,
|
||||
)
|
||||
@system_option
|
||||
@option("--bare", is_flag=True, default=False, help="Minimal output.")
|
||||
@sync_options
|
||||
@pass_state
|
||||
@pass_context
|
||||
def sync(
|
||||
ctx,
|
||||
state,
|
||||
bare=False,
|
||||
user=False,
|
||||
unused=False,
|
||||
**kwargs
|
||||
):
|
||||
def sync(ctx, state, bare=False, user=False, unused=False, **kwargs):
|
||||
"""Installs all packages specified in Pipfile.lock."""
|
||||
from ..core import do_sync
|
||||
|
||||
@@ -641,7 +672,7 @@ def sync(
|
||||
unused=unused,
|
||||
sequential=state.installstate.sequential,
|
||||
pypi_mirror=state.pypi_mirror,
|
||||
system=state.system
|
||||
system=state.system,
|
||||
)
|
||||
if retcode:
|
||||
ctx.abort()
|
||||
@@ -649,7 +680,7 @@ def sync(
|
||||
|
||||
@cli.command(
|
||||
short_help="Uninstalls all packages not specified in Pipfile.lock.",
|
||||
context_settings=CONTEXT_SETTINGS
|
||||
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.")
|
||||
@@ -660,8 +691,14 @@ def sync(
|
||||
def clean(state, dry_run=False, bare=False, user=False):
|
||||
"""Uninstalls all packages not specified in Pipfile.lock."""
|
||||
from ..core import do_clean
|
||||
do_clean(state.project, three=state.three, python=state.python, dry_run=dry_run,
|
||||
system=state.system)
|
||||
|
||||
do_clean(
|
||||
state.project,
|
||||
three=state.three,
|
||||
python=state.python,
|
||||
dry_run=dry_run,
|
||||
system=state.system,
|
||||
)
|
||||
|
||||
|
||||
@cli.command(
|
||||
@@ -675,7 +712,7 @@ def scripts(state):
|
||||
if not state.project.pipfile_exists:
|
||||
echo("No Pipfile present at project home.", err=True)
|
||||
sys.exit(1)
|
||||
scripts = state.project.parsed_pipfile.get('scripts', {})
|
||||
scripts = state.project.parsed_pipfile.get("scripts", {})
|
||||
first_column_width = max(len(word) for word in ["Command"] + list(scripts))
|
||||
second_column_width = max(len(word) for word in ["Script"] + list(scripts.values()))
|
||||
lines = ["{0:<{width}} Script".format("Command", width=first_column_width)]
|
||||
@@ -699,13 +736,13 @@ def verify(state):
|
||||
sys.exit(1)
|
||||
if state.project.get_lockfile_hash() != state.project.calculate_pipfile_hash():
|
||||
echo(
|
||||
'Pipfile.lock is out-of-date. Run {} to update.'.format(
|
||||
"Pipfile.lock is out-of-date. Run {} to update.".format(
|
||||
crayons.yellow("$ pipenv lock", bold=True)
|
||||
),
|
||||
err=True
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
echo(crayons.green('Pipfile.lock is up-to-date.'))
|
||||
echo(crayons.green("Pipfile.lock is up-to-date."))
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
|
||||
+251
-71
@@ -3,17 +3,19 @@ import os
|
||||
from pipenv.project import Project
|
||||
from pipenv.utils.internet import is_valid_url
|
||||
from pipenv.vendor.click import (
|
||||
BadArgumentUsage, BadParameter, Group, Option, argument, echo,
|
||||
make_pass_decorator, option
|
||||
BadArgumentUsage,
|
||||
BadParameter,
|
||||
Group,
|
||||
Option,
|
||||
argument,
|
||||
echo,
|
||||
make_pass_decorator,
|
||||
option,
|
||||
)
|
||||
from pipenv.vendor.click import types as click_types
|
||||
from pipenv.vendor.click_didyoumean import DYMMixin
|
||||
|
||||
|
||||
CONTEXT_SETTINGS = {
|
||||
"help_option_names": ["-h", "--help"],
|
||||
"auto_envvar_prefix": "PIPENV"
|
||||
}
|
||||
CONTEXT_SETTINGS = {"help_option_names": ["-h", "--help"], "auto_envvar_prefix": "PIPENV"}
|
||||
|
||||
|
||||
class PipenvGroup(DYMMixin, Group):
|
||||
@@ -53,6 +55,7 @@ class PipenvGroup(DYMMixin, Group):
|
||||
"""
|
||||
return super().main(*args, **kwargs, windows_expand_args=False)
|
||||
|
||||
|
||||
class State:
|
||||
def __init__(self):
|
||||
self.index = None
|
||||
@@ -102,9 +105,16 @@ def index_option(f):
|
||||
state = ctx.ensure_object(State)
|
||||
state.index = value
|
||||
return value
|
||||
return option('-i', '--index', expose_value=False, envvar="PIP_INDEX_URL",
|
||||
help='Target PyPI-compatible package index url.', nargs=1,
|
||||
callback=callback)(f)
|
||||
|
||||
return option(
|
||||
"-i",
|
||||
"--index",
|
||||
expose_value=False,
|
||||
envvar="PIP_INDEX_URL",
|
||||
help="Target PyPI-compatible package index url.",
|
||||
nargs=1,
|
||||
callback=callback,
|
||||
)(f)
|
||||
|
||||
|
||||
def extra_index_option(f):
|
||||
@@ -112,9 +122,15 @@ def extra_index_option(f):
|
||||
state = ctx.ensure_object(State)
|
||||
state.extra_index_urls.extend(list(value))
|
||||
return value
|
||||
return option("--extra-index-url", multiple=True, expose_value=False,
|
||||
|
||||
return option(
|
||||
"--extra-index-url",
|
||||
multiple=True,
|
||||
expose_value=False,
|
||||
help="URLs to the extra PyPI compatible indexes to query for package look-ups.",
|
||||
callback=callback, envvar="PIP_EXTRA_INDEX_URL")(f)
|
||||
callback=callback,
|
||||
envvar="PIP_EXTRA_INDEX_URL",
|
||||
)(f)
|
||||
|
||||
|
||||
def editable_option(f):
|
||||
@@ -122,11 +138,16 @@ def editable_option(f):
|
||||
state = ctx.ensure_object(State)
|
||||
state.installstate.editables.extend(value)
|
||||
return value
|
||||
return option('-e', '--editable', expose_value=False, multiple=True,
|
||||
callback=callback, type=click_types.STRING, help=(
|
||||
"An editable Python package URL or path, often to a VCS "
|
||||
"repository."
|
||||
))(f)
|
||||
|
||||
return option(
|
||||
"-e",
|
||||
"--editable",
|
||||
expose_value=False,
|
||||
multiple=True,
|
||||
callback=callback,
|
||||
type=click_types.STRING,
|
||||
help="An editable Python package URL or path, often to a VCS repository.",
|
||||
)(f)
|
||||
|
||||
|
||||
def sequential_option(f):
|
||||
@@ -134,9 +155,17 @@ def sequential_option(f):
|
||||
state = ctx.ensure_object(State)
|
||||
state.installstate.sequential = value
|
||||
return value
|
||||
return option("--sequential", is_flag=True, default=False, expose_value=False,
|
||||
|
||||
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, show_envvar=True)(f)
|
||||
callback=callback,
|
||||
type=click_types.BOOL,
|
||||
show_envvar=True,
|
||||
)(f)
|
||||
|
||||
|
||||
def skip_lock_option(f):
|
||||
@@ -144,10 +173,18 @@ def skip_lock_option(f):
|
||||
state = ctx.ensure_object(State)
|
||||
state.installstate.skip_lock = value
|
||||
return value
|
||||
return option("--skip-lock", is_flag=True, default=False, expose_value=False,
|
||||
|
||||
return option(
|
||||
"--skip-lock",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
expose_value=False,
|
||||
help="Skip locking mechanisms and use the Pipfile instead during operation.",
|
||||
envvar="PIPENV_SKIP_LOCK", callback=callback, type=click_types.BOOL,
|
||||
show_envvar=True)(f)
|
||||
envvar="PIPENV_SKIP_LOCK",
|
||||
callback=callback,
|
||||
type=click_types.BOOL,
|
||||
show_envvar=True,
|
||||
)(f)
|
||||
|
||||
|
||||
def keep_outdated_option(f):
|
||||
@@ -155,9 +192,17 @@ def keep_outdated_option(f):
|
||||
state = ctx.ensure_object(State)
|
||||
state.installstate.keep_outdated = value
|
||||
return value
|
||||
return option("--keep-outdated", is_flag=True, default=False, expose_value=False,
|
||||
|
||||
return option(
|
||||
"--keep-outdated",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
expose_value=False,
|
||||
help="Keep out-dated dependencies from being updated in Pipfile.lock.",
|
||||
callback=callback, type=click_types.BOOL, show_envvar=True)(f)
|
||||
callback=callback,
|
||||
type=click_types.BOOL,
|
||||
show_envvar=True,
|
||||
)(f)
|
||||
|
||||
|
||||
def selective_upgrade_option(f):
|
||||
@@ -165,9 +210,16 @@ def selective_upgrade_option(f):
|
||||
state = ctx.ensure_object(State)
|
||||
state.installstate.selective_upgrade = value
|
||||
return value
|
||||
return option("--selective-upgrade", is_flag=True, default=False, type=click_types.BOOL,
|
||||
help="Update specified packages.", callback=callback,
|
||||
expose_value=False)(f)
|
||||
|
||||
return option(
|
||||
"--selective-upgrade",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
type=click_types.BOOL,
|
||||
help="Update specified packages.",
|
||||
callback=callback,
|
||||
expose_value=False,
|
||||
)(f)
|
||||
|
||||
|
||||
def ignore_pipfile_option(f):
|
||||
@@ -175,9 +227,17 @@ def ignore_pipfile_option(f):
|
||||
state = ctx.ensure_object(State)
|
||||
state.installstate.ignore_pipfile = value
|
||||
return value
|
||||
return option("--ignore-pipfile", is_flag=True, default=False, expose_value=False,
|
||||
|
||||
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, show_envvar=True)(f)
|
||||
callback=callback,
|
||||
type=click_types.BOOL,
|
||||
show_envvar=True,
|
||||
)(f)
|
||||
|
||||
|
||||
def _dev_option(f, help_text):
|
||||
@@ -185,9 +245,18 @@ def _dev_option(f, help_text):
|
||||
state = ctx.ensure_object(State)
|
||||
state.installstate.dev = value
|
||||
return value
|
||||
return option("--dev", "-d", is_flag=True, default=False, type=click_types.BOOL,
|
||||
help=help_text, callback=callback,
|
||||
expose_value=False, show_envvar=True)(f)
|
||||
|
||||
return option(
|
||||
"--dev",
|
||||
"-d",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
type=click_types.BOOL,
|
||||
help=help_text,
|
||||
callback=callback,
|
||||
expose_value=False,
|
||||
show_envvar=True,
|
||||
)(f)
|
||||
|
||||
|
||||
def install_dev_option(f):
|
||||
@@ -199,7 +268,9 @@ def lock_dev_option(f):
|
||||
|
||||
|
||||
def uninstall_dev_option(f):
|
||||
return _dev_option(f, "Deprecated (as it has no effect). May be removed in a future release.")
|
||||
return _dev_option(
|
||||
f, "Deprecated (as it has no effect). May be removed in a future release."
|
||||
)
|
||||
|
||||
|
||||
def pre_option(f):
|
||||
@@ -207,8 +278,16 @@ def pre_option(f):
|
||||
state = ctx.ensure_object(State)
|
||||
state.installstate.pre = value
|
||||
return value
|
||||
return option("--pre", is_flag=True, default=False, help="Allow pre-releases.",
|
||||
callback=callback, type=click_types.BOOL, expose_value=False)(f)
|
||||
|
||||
return option(
|
||||
"--pre",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Allow pre-releases.",
|
||||
callback=callback,
|
||||
type=click_types.BOOL,
|
||||
expose_value=False,
|
||||
)(f)
|
||||
|
||||
|
||||
def package_arg(f):
|
||||
@@ -216,8 +295,14 @@ def package_arg(f):
|
||||
state = ctx.ensure_object(State)
|
||||
state.installstate.packages.extend(value)
|
||||
return value
|
||||
return argument('packages', nargs=-1, callback=callback, expose_value=False,
|
||||
type=click_types.STRING)(f)
|
||||
|
||||
return argument(
|
||||
"packages",
|
||||
nargs=-1,
|
||||
callback=callback,
|
||||
expose_value=False,
|
||||
type=click_types.STRING,
|
||||
)(f)
|
||||
|
||||
|
||||
def three_option(f):
|
||||
@@ -226,9 +311,15 @@ def three_option(f):
|
||||
if value is not None:
|
||||
state.three = value
|
||||
return value
|
||||
return option("--three", is_flag=True, default=None,
|
||||
help="Use Python 3/2 when creating virtualenv.", callback=callback,
|
||||
expose_value=False)(f)
|
||||
|
||||
return option(
|
||||
"--three",
|
||||
is_flag=True,
|
||||
default=None,
|
||||
help="Use Python 3 when creating virtualenv.",
|
||||
callback=callback,
|
||||
expose_value=False,
|
||||
)(f)
|
||||
|
||||
|
||||
def python_option(f):
|
||||
@@ -237,10 +328,17 @@ def python_option(f):
|
||||
if value is not None:
|
||||
state.python = validate_python_path(ctx, param, value)
|
||||
return value
|
||||
return option("--python", default="", nargs=1, callback=callback,
|
||||
|
||||
return option(
|
||||
"--python",
|
||||
default="",
|
||||
nargs=1,
|
||||
callback=callback,
|
||||
help="Specify which version of Python virtualenv should use.",
|
||||
expose_value=False, allow_from_autoenv=False,
|
||||
type=click_types.STRING)(f)
|
||||
expose_value=False,
|
||||
allow_from_autoenv=False,
|
||||
type=click_types.STRING,
|
||||
)(f)
|
||||
|
||||
|
||||
def pypi_mirror_option(f):
|
||||
@@ -250,8 +348,14 @@ def pypi_mirror_option(f):
|
||||
if value is not None:
|
||||
state.pypi_mirror = validate_pypi_mirror(ctx, param, value)
|
||||
return value
|
||||
return option("--pypi-mirror", nargs=1, callback=callback,
|
||||
help="Specify a PyPI mirror.", expose_value=False)(f)
|
||||
|
||||
return option(
|
||||
"--pypi-mirror",
|
||||
nargs=1,
|
||||
callback=callback,
|
||||
help="Specify a PyPI mirror.",
|
||||
expose_value=False,
|
||||
)(f)
|
||||
|
||||
|
||||
def verbose_option(f):
|
||||
@@ -261,12 +365,20 @@ def verbose_option(f):
|
||||
if state.quiet:
|
||||
raise BadArgumentUsage(
|
||||
"--verbose and --quiet are mutually exclusive! Please choose one!",
|
||||
ctx=ctx
|
||||
ctx=ctx,
|
||||
)
|
||||
state.verbose = True
|
||||
setup_verbosity(ctx, param, 1)
|
||||
return option("--verbose", "-v", is_flag=True, expose_value=False,
|
||||
callback=callback, help="Verbose mode.", type=click_types.BOOL)(f)
|
||||
|
||||
return option(
|
||||
"--verbose",
|
||||
"-v",
|
||||
is_flag=True,
|
||||
expose_value=False,
|
||||
callback=callback,
|
||||
help="Verbose mode.",
|
||||
type=click_types.BOOL,
|
||||
)(f)
|
||||
|
||||
|
||||
def quiet_option(f):
|
||||
@@ -276,12 +388,20 @@ def quiet_option(f):
|
||||
if state.verbose:
|
||||
raise BadArgumentUsage(
|
||||
"--verbose and --quiet are mutually exclusive! Please choose one!",
|
||||
ctx=ctx
|
||||
ctx=ctx,
|
||||
)
|
||||
state.quiet = True
|
||||
setup_verbosity(ctx, param, -1)
|
||||
return option("--quiet", "-q", is_flag=True, expose_value=False,
|
||||
callback=callback, help="Quiet mode.", type=click_types.BOOL)(f)
|
||||
|
||||
return option(
|
||||
"--quiet",
|
||||
"-q",
|
||||
is_flag=True,
|
||||
expose_value=False,
|
||||
callback=callback,
|
||||
help="Quiet mode.",
|
||||
type=click_types.BOOL,
|
||||
)(f)
|
||||
|
||||
|
||||
def site_packages_option(f):
|
||||
@@ -290,9 +410,16 @@ def site_packages_option(f):
|
||||
validate_bool_or_none(ctx, param, value)
|
||||
state.site_packages = value
|
||||
return value
|
||||
return option("--site-packages/--no-site-packages", is_flag=True, default=None,
|
||||
help="Enable site-packages for the virtualenv.", callback=callback,
|
||||
expose_value=False, show_envvar=True)(f)
|
||||
|
||||
return option(
|
||||
"--site-packages/--no-site-packages",
|
||||
is_flag=True,
|
||||
default=None,
|
||||
help="Enable site-packages for the virtualenv.",
|
||||
callback=callback,
|
||||
expose_value=False,
|
||||
show_envvar=True,
|
||||
)(f)
|
||||
|
||||
|
||||
def clear_option(f):
|
||||
@@ -300,9 +427,16 @@ def clear_option(f):
|
||||
state = ctx.ensure_object(State)
|
||||
state.clear = value
|
||||
return value
|
||||
return option("--clear", is_flag=True, callback=callback, type=click_types.BOOL,
|
||||
|
||||
return option(
|
||||
"--clear",
|
||||
is_flag=True,
|
||||
callback=callback,
|
||||
type=click_types.BOOL,
|
||||
help="Clears caches (pipenv, pip).",
|
||||
expose_value=False, show_envvar=True)(f)
|
||||
expose_value=False,
|
||||
show_envvar=True,
|
||||
)(f)
|
||||
|
||||
|
||||
def system_option(f):
|
||||
@@ -311,9 +445,17 @@ def system_option(f):
|
||||
if value is not None:
|
||||
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,
|
||||
show_envvar=True)(f)
|
||||
|
||||
return option(
|
||||
"--system",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="System pip management.",
|
||||
callback=callback,
|
||||
type=click_types.BOOL,
|
||||
expose_value=False,
|
||||
show_envvar=True,
|
||||
)(f)
|
||||
|
||||
|
||||
def requirementstxt_option(f):
|
||||
@@ -322,9 +464,17 @@ def requirementstxt_option(f):
|
||||
if value:
|
||||
state.installstate.requirementstxt = value
|
||||
return value
|
||||
return option("--requirements", "-r", nargs=1, default="", expose_value=False,
|
||||
help="Import a requirements.txt file.", callback=callback,
|
||||
type=click_types.STRING)(f)
|
||||
|
||||
return option(
|
||||
"--requirements",
|
||||
"-r",
|
||||
nargs=1,
|
||||
default="",
|
||||
expose_value=False,
|
||||
help="Import a requirements.txt file.",
|
||||
callback=callback,
|
||||
type=click_types.STRING,
|
||||
)(f)
|
||||
|
||||
|
||||
def emit_requirements_flag(f):
|
||||
@@ -333,8 +483,16 @@ def emit_requirements_flag(f):
|
||||
if value:
|
||||
state.lockoptions.emit_requirements = value
|
||||
return value
|
||||
return option("--requirements", "-r", default=False, is_flag=True, expose_value=False,
|
||||
help="Generate output in requirements.txt format.", callback=callback)(f)
|
||||
|
||||
return option(
|
||||
"--requirements",
|
||||
"-r",
|
||||
default=False,
|
||||
is_flag=True,
|
||||
expose_value=False,
|
||||
help="Generate output in requirements.txt format.",
|
||||
callback=callback,
|
||||
)(f)
|
||||
|
||||
|
||||
def emit_requirements_header_flag(f):
|
||||
@@ -343,8 +501,15 @@ def emit_requirements_header_flag(f):
|
||||
if value:
|
||||
state.lockoptions.emit_requirements_header = value
|
||||
return value
|
||||
return option("--header/--no-header", default=True, is_flag=True, expose_value=False,
|
||||
help="Add header to generated requirements", callback=callback)(f)
|
||||
|
||||
return option(
|
||||
"--header/--no-header",
|
||||
default=True,
|
||||
is_flag=True,
|
||||
expose_value=False,
|
||||
help="Add header to generated requirements",
|
||||
callback=callback,
|
||||
)(f)
|
||||
|
||||
|
||||
def dev_only_flag(f):
|
||||
@@ -353,8 +518,15 @@ def dev_only_flag(f):
|
||||
if value:
|
||||
state.lockoptions.dev_only = value
|
||||
return value
|
||||
return option("--dev-only", default=False, is_flag=True, expose_value=False,
|
||||
help="Emit development dependencies *only* (overrides --dev)", callback=callback)(f)
|
||||
|
||||
return option(
|
||||
"--dev-only",
|
||||
default=False,
|
||||
is_flag=True,
|
||||
expose_value=False,
|
||||
help="Emit development dependencies *only* (overrides --dev)",
|
||||
callback=callback,
|
||||
)(f)
|
||||
|
||||
|
||||
def deploy_option(f):
|
||||
@@ -362,15 +534,23 @@ def deploy_option(f):
|
||||
state = ctx.ensure_object(State)
|
||||
state.installstate.deploy = value
|
||||
return value
|
||||
return option("--deploy", is_flag=True, default=False, type=click_types.BOOL,
|
||||
help="Abort if the Pipfile.lock is out-of-date, or Python version is"
|
||||
" wrong.", callback=callback, expose_value=False)(f)
|
||||
|
||||
return option(
|
||||
"--deploy",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
type=click_types.BOOL,
|
||||
help="Abort if the Pipfile.lock is out-of-date, or Python version is wrong.",
|
||||
callback=callback,
|
||||
expose_value=False,
|
||||
)(f)
|
||||
|
||||
|
||||
def setup_verbosity(ctx, param, value):
|
||||
if not value:
|
||||
return
|
||||
import logging
|
||||
|
||||
loggers = ("pip",)
|
||||
if value == 1:
|
||||
for logger in loggers:
|
||||
|
||||
+6
-4
@@ -94,7 +94,9 @@ class Script(object):
|
||||
|
||||
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),
|
||||
))
|
||||
return " ".join(
|
||||
itertools.chain(
|
||||
[_quote_if_contains(self.command, r"[\s^()]")],
|
||||
(_quote_if_contains(arg, r"[\s^]") for arg in self.args),
|
||||
)
|
||||
)
|
||||
|
||||
+384
-206
File diff suppressed because it is too large
Load Diff
+211
-107
@@ -12,21 +12,17 @@ from sysconfig import get_paths, get_python_version
|
||||
import pkg_resources
|
||||
|
||||
import pipenv
|
||||
|
||||
from pipenv.environments import is_type_checking
|
||||
from pipenv.utils.shell import make_posix, normalize_path
|
||||
from pipenv.utils.processes import subprocess_run
|
||||
from pipenv.utils.indexes import prepare_pip_source_args
|
||||
from pipenv.utils.processes import subprocess_run
|
||||
from pipenv.utils.shell import make_posix, normalize_path
|
||||
from pipenv.vendor import vistir
|
||||
from pipenv.vendor.cached_property import cached_property
|
||||
from pipenv.vendor.packaging.utils import canonicalize_name
|
||||
|
||||
|
||||
if is_type_checking():
|
||||
from types import ModuleType
|
||||
from typing import (
|
||||
ContextManager, Dict, Generator, List, Optional, Set, Union
|
||||
)
|
||||
from typing import ContextManager, Dict, Generator, List, Optional, Set, Union
|
||||
|
||||
import pip_shims.shims
|
||||
import tomlkit
|
||||
@@ -47,10 +43,10 @@ class Environment:
|
||||
base_working_set=None, # type: pkg_resources.WorkingSet
|
||||
pipfile=None, # type: Optional[Union[tomlkit.toml_document.TOMLDocument, TPipfile]]
|
||||
sources=None, # type: Optional[List[TSource]]
|
||||
project=None # type: Optional[Project]
|
||||
project=None, # type: Optional[Project]
|
||||
):
|
||||
super().__init__()
|
||||
self._modules = {'pkg_resources': pkg_resources, 'pipenv': pipenv}
|
||||
self._modules = {"pkg_resources": pkg_resources, "pipenv": pipenv}
|
||||
self.base_working_set = base_working_set if base_working_set else BASE_WORKING_SET
|
||||
prefix = normalize_path(prefix)
|
||||
self._python = None
|
||||
@@ -82,9 +78,10 @@ class Environment:
|
||||
self._modules[name] = importlib.import_module(name)
|
||||
module = self._modules[name]
|
||||
if not module:
|
||||
dist = next(iter(
|
||||
dist for dist in self.base_working_set if dist.project_name == name
|
||||
), None)
|
||||
dist = next(
|
||||
iter(dist for dist in self.base_working_set if dist.project_name == name),
|
||||
None,
|
||||
)
|
||||
if dist:
|
||||
dist.activate()
|
||||
module = importlib.import_module(name)
|
||||
@@ -152,7 +149,9 @@ class Environment:
|
||||
if not os.path.exists(include_dir):
|
||||
include_dirs = self.get_include_path()
|
||||
if include_dirs:
|
||||
include_path = include_dirs.get("include", include_dirs.get("platinclude"))
|
||||
include_path = include_dirs.get(
|
||||
"include", include_dirs.get("platinclude")
|
||||
)
|
||||
if not include_path:
|
||||
return {}
|
||||
include_dir = Path(include_path)
|
||||
@@ -169,7 +168,8 @@ class Environment:
|
||||
base, leaf = os.path.split(path)
|
||||
base, parent = os.path.split(base)
|
||||
leaf = os.path.join(parent, leaf).replace(
|
||||
replace_version, self.python_info.get("py_version_short", get_python_version())
|
||||
replace_version,
|
||||
self.python_info.get("py_version_short", get_python_version()),
|
||||
)
|
||||
return os.path.join(base, leaf)
|
||||
return path
|
||||
@@ -213,16 +213,21 @@ class Environment:
|
||||
try:
|
||||
paths = self.get_paths()
|
||||
except Exception:
|
||||
install_scheme = 'nt' if (os.name == 'nt') else 'posix_prefix'
|
||||
paths = get_paths(install_scheme, vars={
|
||||
'base': prefix,
|
||||
'platbase': prefix,
|
||||
})
|
||||
install_scheme = "nt" if (os.name == "nt") else "posix_prefix"
|
||||
paths = get_paths(
|
||||
install_scheme,
|
||||
vars={
|
||||
"base": prefix,
|
||||
"platbase": prefix,
|
||||
},
|
||||
)
|
||||
current_version = get_python_version()
|
||||
try:
|
||||
for k in list(paths.keys()):
|
||||
if not os.path.exists(paths[k]):
|
||||
paths[k] = self._replace_parent_version(paths[k], current_version)
|
||||
paths[k] = self._replace_parent_version(
|
||||
paths[k], current_version
|
||||
)
|
||||
except OSError:
|
||||
# Sometimes virtualenvs are made using virtualenv interpreters and there is no
|
||||
# include directory, which will cause this approach to fail. This failsafe
|
||||
@@ -231,11 +236,14 @@ class Environment:
|
||||
paths.update(self.get_lib_paths())
|
||||
paths["scripts"] = self.script_basedir
|
||||
if not paths:
|
||||
install_scheme = 'nt' if (os.name == 'nt') else 'posix_prefix'
|
||||
paths = get_paths(install_scheme, vars={
|
||||
'base': prefix,
|
||||
'platbase': prefix,
|
||||
})
|
||||
install_scheme = "nt" if (os.name == "nt") else "posix_prefix"
|
||||
paths = get_paths(
|
||||
install_scheme,
|
||||
vars={
|
||||
"base": prefix,
|
||||
"platbase": prefix,
|
||||
},
|
||||
)
|
||||
if not os.path.exists(paths["purelib"]) and not os.path.exists(paths["platlib"]):
|
||||
lib_paths = self.get_lib_paths()
|
||||
paths.update(lib_paths)
|
||||
@@ -249,7 +257,7 @@ class Environment:
|
||||
else:
|
||||
lib_dirs = purelib + os.pathsep + platlib
|
||||
paths["libdir"] = purelib
|
||||
paths['PYTHONPATH'] = os.pathsep.join(["", ".", lib_dirs])
|
||||
paths["PYTHONPATH"] = os.pathsep.join(["", ".", lib_dirs])
|
||||
paths["libdirs"] = lib_dirs
|
||||
return paths
|
||||
|
||||
@@ -258,11 +266,14 @@ class Environment:
|
||||
# type: () -> str
|
||||
"""Path to the environment scripts dir"""
|
||||
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,
|
||||
'platbase': prefix,
|
||||
})
|
||||
install_scheme = "nt" if (os.name == "nt") else "posix_prefix"
|
||||
paths = get_paths(
|
||||
install_scheme,
|
||||
vars={
|
||||
"base": prefix,
|
||||
"platbase": prefix,
|
||||
},
|
||||
)
|
||||
return paths["scripts"]
|
||||
|
||||
@property
|
||||
@@ -291,20 +302,30 @@ class Environment:
|
||||
"""
|
||||
|
||||
from .vendor.vistir.compat import JSONDecodeError
|
||||
|
||||
current_executable = Path(sys.executable).as_posix()
|
||||
if not self.python or self.python == current_executable:
|
||||
return sys.path
|
||||
elif any([sys.prefix == self.prefix, not self.is_venv]):
|
||||
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, _ = vistir.misc.run(
|
||||
cmd_args,
|
||||
return_object=False,
|
||||
nospin=True,
|
||||
block=True,
|
||||
combine_stderr=False,
|
||||
write_to_stdout=False,
|
||||
)
|
||||
try:
|
||||
path = json.loads(path.strip())
|
||||
except JSONDecodeError:
|
||||
path = sys.path
|
||||
return path
|
||||
|
||||
def build_command(self, python_lib=False, python_inc=False, scripts=False, py_version=False):
|
||||
def build_command(
|
||||
self, python_lib=False, python_inc=False, scripts=False, py_version=False
|
||||
):
|
||||
# type: (bool, bool, bool, bool) -> str
|
||||
"""Build the text for running a command in the given environment
|
||||
|
||||
@@ -332,16 +353,26 @@ class Environment:
|
||||
dist_prefix = f"{key}lib"
|
||||
# XXX: We need to get 'stdlib' or 'platstdlib'
|
||||
sys_prefix = "{}stdlib".format("" if key == "pure" else key)
|
||||
pylib_lines.append(f"u'{dist_prefix}': u'{{{{0}}}}'.format({distutils_line.format(var, val)})")
|
||||
pylib_lines.append(f"u'{sys_prefix}': u'{{{{0}}}}'.format({sysconfig_line.format(sys_prefix)})")
|
||||
pylib_lines.append(
|
||||
f"u'{dist_prefix}': u'{{{{0}}}}'.format({distutils_line.format(var, val)})"
|
||||
)
|
||||
pylib_lines.append(
|
||||
f"u'{sys_prefix}': u'{{{{0}}}}'.format({sysconfig_line.format(sys_prefix)})"
|
||||
)
|
||||
if python_inc:
|
||||
for key, var, val in (("include", "inc", "0"), ("platinclude", "inc", "1")):
|
||||
pylib_lines.append(f"u'{key}': u'{{{{0}}}}'.format({distutils_line.format(var, val)})")
|
||||
pylib_lines.append(
|
||||
f"u'{key}': u'{{{{0}}}}'.format({distutils_line.format(var, val)})"
|
||||
)
|
||||
lines = pylib_lines + pyinc_lines
|
||||
if scripts:
|
||||
lines.append("u'scripts': u'{{0}}'.format(%s)" % sysconfig_line.format("scripts"))
|
||||
lines.append(
|
||||
"u'scripts': u'{{0}}'.format(%s)" % sysconfig_line.format("scripts")
|
||||
)
|
||||
if py_version:
|
||||
lines.append("u'py_version_short': u'{{0}}'.format(distutils.sysconfig.get_python_version()),")
|
||||
lines.append(
|
||||
"u'py_version_short': u'{{0}}'.format(distutils.sysconfig.get_python_version()),"
|
||||
)
|
||||
lines_as_str = ",".join(lines)
|
||||
py_command = py_command % lines_as_str
|
||||
return py_command
|
||||
@@ -357,7 +388,9 @@ class Environment:
|
||||
tmpfile = vistir.path.create_tracked_tempfile(suffix=".json")
|
||||
tmpfile.close()
|
||||
tmpfile_path = make_posix(tmpfile.name)
|
||||
py_command = self.build_command(python_lib=True, python_inc=True, scripts=True, py_version=True)
|
||||
py_command = self.build_command(
|
||||
python_lib=True, python_inc=True, scripts=True, py_version=True
|
||||
)
|
||||
command = [self.python, "-c", py_command.format(tmpfile_path)]
|
||||
c = subprocess_run(command)
|
||||
if c.returncode == 0:
|
||||
@@ -366,7 +399,14 @@ class Environment:
|
||||
paths = json.load(fh)
|
||||
if "purelib" in paths:
|
||||
paths["libdir"] = paths["purelib"] = make_posix(paths["purelib"])
|
||||
for key in ("platlib", "scripts", "platstdlib", "stdlib", "include", "platinclude"):
|
||||
for key in (
|
||||
"platlib",
|
||||
"scripts",
|
||||
"platstdlib",
|
||||
"stdlib",
|
||||
"include",
|
||||
"platinclude",
|
||||
):
|
||||
if key in paths:
|
||||
paths[key] = make_posix(paths[key])
|
||||
return paths
|
||||
@@ -405,16 +445,27 @@ class Environment:
|
||||
if not paths:
|
||||
if not self.prefix.joinpath("lib").exists():
|
||||
return {}
|
||||
stdlib_path = next(iter([
|
||||
p for p in self.prefix.joinpath("lib").iterdir()
|
||||
stdlib_path = next(
|
||||
iter(
|
||||
[
|
||||
p
|
||||
for p in self.prefix.joinpath("lib").iterdir()
|
||||
if p.name.startswith("python")
|
||||
]), None)
|
||||
]
|
||||
),
|
||||
None,
|
||||
)
|
||||
lib_path = None
|
||||
if stdlib_path:
|
||||
lib_path = next(iter([
|
||||
p.as_posix() for p in stdlib_path.iterdir()
|
||||
lib_path = next(
|
||||
iter(
|
||||
[
|
||||
p.as_posix()
|
||||
for p in stdlib_path.iterdir()
|
||||
if p.name == "site-packages"
|
||||
]))
|
||||
]
|
||||
)
|
||||
)
|
||||
paths = {"stdlib": stdlib_path.as_posix()}
|
||||
if lib_path:
|
||||
paths["purelib"] = lib_path
|
||||
@@ -503,9 +554,10 @@ class Environment:
|
||||
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)
|
||||
|
||||
pip = next(
|
||||
iter(pkg for pkg in self.get_installed_packages() if pkg.key == "pip"), None
|
||||
)
|
||||
if pip is not None:
|
||||
return parse_version(pip.version)
|
||||
return parse_version("20.2")
|
||||
@@ -542,8 +594,12 @@ class Environment:
|
||||
:rtype: iterator
|
||||
"""
|
||||
|
||||
pip_target_dir = os.environ.get('PIP_TARGET')
|
||||
libdirs = [pip_target_dir] if pip_target_dir else self.base_paths["libdirs"].split(os.pathsep)
|
||||
pip_target_dir = os.environ.get("PIP_TARGET")
|
||||
libdirs = (
|
||||
[pip_target_dir]
|
||||
if pip_target_dir
|
||||
else self.base_paths["libdirs"].split(os.pathsep)
|
||||
)
|
||||
dists = (pkg_resources.find_distributions(libdir) for libdir in libdirs)
|
||||
yield from itertools.chain.from_iterable(dists)
|
||||
|
||||
@@ -575,8 +631,10 @@ class Environment:
|
||||
# type: (pkg_resources.Distribution) -> bool
|
||||
"""Determine whether the supplied distribution is in the environment."""
|
||||
from .environments import normalize_pipfile_path as _normalized
|
||||
|
||||
prefixes = [
|
||||
_normalized(prefix) for prefix in self.base_paths["libdirs"].split(os.pathsep)
|
||||
_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)
|
||||
@@ -590,7 +648,8 @@ class Environment:
|
||||
"""Returns all of the installed packages in a given environment"""
|
||||
workingset = self.get_working_set()
|
||||
packages = [
|
||||
pkg for pkg in workingset
|
||||
pkg
|
||||
for pkg in workingset
|
||||
if self.dist_is_in_project(pkg) and pkg.key != "python"
|
||||
]
|
||||
return packages
|
||||
@@ -606,20 +665,23 @@ class Environment:
|
||||
pip_options.cache_dir = self.project.s.PIPENV_CACHE_DIR
|
||||
pip_options.pre = self.pipfile.get("pre", pre)
|
||||
with pip_command._build_session(pip_options) as session:
|
||||
finder = get_package_finder(install_cmd=pip_command, options=pip_options, session=session)
|
||||
finder = get_package_finder(
|
||||
install_cmd=pip_command, options=pip_options, session=session
|
||||
)
|
||||
yield finder
|
||||
|
||||
def get_package_info(self, pre=False):
|
||||
# type: (bool) -> Generator[pkg_resources.Distribution, None, None]
|
||||
from .vendor.pip_shims.shims import parse_version, pip_version
|
||||
|
||||
dependency_links = []
|
||||
packages = self.get_installed_packages()
|
||||
# This code is borrowed from pip's current implementation
|
||||
if parse_version(pip_version) < parse_version("19.0"):
|
||||
for dist in packages:
|
||||
if dist.has_metadata('dependency_links.txt'):
|
||||
if dist.has_metadata("dependency_links.txt"):
|
||||
dependency_links.extend(
|
||||
dist.get_metadata_lines('dependency_links.txt')
|
||||
dist.get_metadata_lines("dependency_links.txt")
|
||||
)
|
||||
|
||||
with self.get_finder() as finder:
|
||||
@@ -627,24 +689,29 @@ class Environment:
|
||||
finder.add_dependency_links(dependency_links)
|
||||
|
||||
for dist in packages:
|
||||
typ = 'unknown'
|
||||
typ = "unknown"
|
||||
all_candidates = finder.find_all_candidates(dist.key)
|
||||
if not self.pipfile.get("pre", finder.allow_all_prereleases):
|
||||
# Remove prereleases
|
||||
all_candidates = [
|
||||
candidate for candidate in all_candidates
|
||||
candidate
|
||||
for candidate in all_candidates
|
||||
if not candidate.version.is_prerelease
|
||||
]
|
||||
|
||||
if not all_candidates:
|
||||
continue
|
||||
candidate_evaluator = finder.make_candidate_evaluator(project_name=dist.key)
|
||||
best_candidate_result = candidate_evaluator.compute_best_candidate(all_candidates)
|
||||
candidate_evaluator = finder.make_candidate_evaluator(
|
||||
project_name=dist.key
|
||||
)
|
||||
best_candidate_result = candidate_evaluator.compute_best_candidate(
|
||||
all_candidates
|
||||
)
|
||||
remote_version = best_candidate_result.best_candidate.version
|
||||
if best_candidate_result.best_candidate.link.is_wheel:
|
||||
typ = 'wheel'
|
||||
typ = "wheel"
|
||||
else:
|
||||
typ = 'sdist'
|
||||
typ = "sdist"
|
||||
# This is dirty but makes the rest of the code much cleaner
|
||||
dist.latest_version = remote_version
|
||||
dist.latest_filetype = typ
|
||||
@@ -653,7 +720,8 @@ class Environment:
|
||||
def get_outdated_packages(self, pre=False):
|
||||
# type: (bool) -> List[pkg_resources.Distribution]
|
||||
return [
|
||||
pkg for pkg in self.get_package_info(pre=pre)
|
||||
pkg
|
||||
for pkg in self.get_package_info(pre=pre)
|
||||
if pkg.latest_version._key > pkg.parsed_version._key
|
||||
]
|
||||
|
||||
@@ -664,15 +732,16 @@ class Environment:
|
||||
|
||||
d = node.as_dict()
|
||||
if parent:
|
||||
d['required_version'] = node.version_spec if node.version_spec else 'Any'
|
||||
d["required_version"] = node.version_spec if node.version_spec else "Any"
|
||||
else:
|
||||
d['required_version'] = d['installed_version']
|
||||
d["required_version"] = d["installed_version"]
|
||||
|
||||
get_children = lambda n: key_tree.get(n.key, []) # noqa
|
||||
|
||||
d['dependencies'] = [
|
||||
cls._get_requirements_for_package(c, key_tree, parent=node,
|
||||
chain=chain+[c.project_name])
|
||||
d["dependencies"] = [
|
||||
cls._get_requirements_for_package(
|
||||
c, key_tree, parent=node, chain=chain + [c.project_name]
|
||||
)
|
||||
for c in get_children(node)
|
||||
if c.project_name not in chain
|
||||
]
|
||||
@@ -701,7 +770,7 @@ class Environment:
|
||||
new_node = {
|
||||
"package_name": node["package_name"],
|
||||
"installed_version": node["installed_version"],
|
||||
"required_version": node["required_version"]
|
||||
"required_version": node["required_version"],
|
||||
}
|
||||
for dependency in node.get("dependencies", []):
|
||||
for dep in cls.reverse_dependency(dependency):
|
||||
@@ -712,6 +781,7 @@ class Environment:
|
||||
|
||||
def reverse_dependencies(self):
|
||||
from vistir.misc import chunked, unnest
|
||||
|
||||
rdeps = {}
|
||||
for req in self.get_package_requirements():
|
||||
for d in self.reverse_dependency(req):
|
||||
@@ -720,7 +790,7 @@ class Environment:
|
||||
pkg = {
|
||||
name: {
|
||||
"installed": d["installed_version"],
|
||||
"required": d["required_version"]
|
||||
"required": d["required_version"],
|
||||
}
|
||||
}
|
||||
parents = tuple(d.get("parent", ()))
|
||||
@@ -762,21 +832,26 @@ class Environment:
|
||||
def is_satisfied(self, req):
|
||||
match = next(
|
||||
iter(
|
||||
d for d in self.get_distributions()
|
||||
d
|
||||
for d in self.get_distributions()
|
||||
if canonicalize_name(d.project_name) == req.normalized_name
|
||||
), None
|
||||
),
|
||||
None,
|
||||
)
|
||||
if match is not None:
|
||||
if req.editable and req.line_instance.is_local and self.find_egg(match):
|
||||
requested_path = req.line_instance.path
|
||||
return requested_path and vistir.compat.samefile(requested_path, match.location)
|
||||
return requested_path and vistir.compat.samefile(
|
||||
requested_path, match.location
|
||||
)
|
||||
elif match.has_metadata("direct_url.json"):
|
||||
direct_url_metadata = json.loads(match.get_metadata("direct_url.json"))
|
||||
commit_id = direct_url_metadata.get("vcs_info", {}).get("commit_id", "")
|
||||
vcs_type = direct_url_metadata.get("vcs_info", {}).get("vcs", "")
|
||||
_, pipfile_part = req.as_pipfile().popitem()
|
||||
return (
|
||||
vcs_type == req.vcs and commit_id == req.commit_hash
|
||||
vcs_type == req.vcs
|
||||
and commit_id == req.commit_hash
|
||||
and direct_url_metadata["url"] == pipfile_part[req.vcs]
|
||||
)
|
||||
elif req.is_vcs or req.is_file_or_url:
|
||||
@@ -801,7 +876,13 @@ class Environment:
|
||||
c = None
|
||||
with self.activated():
|
||||
script = vistir.cmdparse.Script.parse(cmd)
|
||||
c = vistir.misc.run(script._parts, return_object=True, nospin=True, cwd=cwd, write_to_stdout=False)
|
||||
c = vistir.misc.run(
|
||||
script._parts,
|
||||
return_object=True,
|
||||
nospin=True,
|
||||
cwd=cwd,
|
||||
write_to_stdout=False,
|
||||
)
|
||||
return c
|
||||
|
||||
def run_py(self, cmd, cwd=os.curdir):
|
||||
@@ -820,7 +901,13 @@ class Environment:
|
||||
else:
|
||||
script = vistir.cmdparse.Script.parse([self.python, "-c"] + list(cmd))
|
||||
with self.activated():
|
||||
c = vistir.misc.run(script._parts, return_object=True, nospin=True, cwd=cwd, write_to_stdout=False)
|
||||
c = vistir.misc.run(
|
||||
script._parts,
|
||||
return_object=True,
|
||||
nospin=True,
|
||||
cwd=cwd,
|
||||
write_to_stdout=False,
|
||||
)
|
||||
return c
|
||||
|
||||
def run_activate_this(self):
|
||||
@@ -865,18 +952,22 @@ class Environment:
|
||||
self.add_dist("pip")
|
||||
prefix = self.prefix.as_posix()
|
||||
with vistir.contextmanagers.temp_environ(), vistir.contextmanagers.temp_path():
|
||||
os.environ["PATH"] = os.pathsep.join([
|
||||
os.environ["PATH"] = os.pathsep.join(
|
||||
[
|
||||
vistir.compat.fs_str(self.script_basedir),
|
||||
vistir.compat.fs_str(self.prefix.as_posix()),
|
||||
os.environ.get("PATH", "")
|
||||
])
|
||||
os.environ.get("PATH", ""),
|
||||
]
|
||||
)
|
||||
os.environ["PYTHONIOENCODING"] = vistir.compat.fs_str("utf-8")
|
||||
os.environ["PYTHONDONTWRITEBYTECODE"] = vistir.compat.fs_str("1")
|
||||
if self.is_venv:
|
||||
os.environ["PYTHONPATH"] = self.base_paths["PYTHONPATH"]
|
||||
os.environ["VIRTUAL_ENV"] = vistir.compat.fs_str(prefix)
|
||||
else:
|
||||
if not self.project.s.PIPENV_USE_SYSTEM and not os.environ.get("VIRTUAL_ENV"):
|
||||
if not self.project.s.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
|
||||
@@ -886,9 +977,9 @@ class Environment:
|
||||
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
|
||||
])
|
||||
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])
|
||||
@@ -905,6 +996,7 @@ class Environment:
|
||||
@cached_property
|
||||
def finders(self):
|
||||
from pipenv.vendor.pythonfinder import Finder
|
||||
|
||||
finders = [
|
||||
Finder(path=self.base_paths["scripts"], global_search=gs, system=False)
|
||||
for gs in (False, True)
|
||||
@@ -929,14 +1021,18 @@ class Environment:
|
||||
install_arg = "install" if not editable else "develop"
|
||||
install_keys = ["headers", "purelib", "platlib", "scripts", "data"]
|
||||
install_args = [
|
||||
self.environment.python, "-u", "-c", SETUPTOOLS_SHIM % setup_path,
|
||||
install_arg, "--single-version-externally-managed", "--no-deps",
|
||||
"--prefix={}".format(self.base_paths["prefix"]), "--no-warn-script-location"
|
||||
self.environment.python,
|
||||
"-u",
|
||||
"-c",
|
||||
SETUPTOOLS_SHIM % setup_path,
|
||||
install_arg,
|
||||
"--single-version-externally-managed",
|
||||
"--no-deps",
|
||||
"--prefix={}".format(self.base_paths["prefix"]),
|
||||
"--no-warn-script-location",
|
||||
]
|
||||
for key in install_keys:
|
||||
install_args.append(
|
||||
f"--install-{key}={self.base_paths[key]}"
|
||||
)
|
||||
install_args.append(f"--install-{key}={self.base_paths[key]}")
|
||||
return install_args
|
||||
|
||||
def install(self, requirements):
|
||||
@@ -944,28 +1040,33 @@ class Environment:
|
||||
requirements = [requirements]
|
||||
with self.get_finder() as finder:
|
||||
args = []
|
||||
for format_control in ('no_binary', 'only_binary'):
|
||||
for format_control in ("no_binary", "only_binary"):
|
||||
formats = getattr(finder.format_control, format_control)
|
||||
args.extend(('--' + format_control.replace('_', '-'),
|
||||
','.join(sorted(formats or {':none:'}))))
|
||||
args.extend(
|
||||
(
|
||||
"--" + format_control.replace("_", "-"),
|
||||
",".join(sorted(formats or {":none:"})),
|
||||
)
|
||||
)
|
||||
if finder.index_urls:
|
||||
args.extend(['-i', finder.index_urls[0]])
|
||||
args.extend(["-i", finder.index_urls[0]])
|
||||
for extra_index in finder.index_urls[1:]:
|
||||
args.extend(['--extra-index-url', extra_index])
|
||||
args.extend(["--extra-index-url", extra_index])
|
||||
else:
|
||||
args.append('--no-index')
|
||||
args.append("--no-index")
|
||||
for link in finder.find_links:
|
||||
args.extend(['--find-links', link])
|
||||
args.extend(["--find-links", link])
|
||||
for _, host, _ in finder.secure_origins:
|
||||
args.extend(['--trusted-host', host])
|
||||
args.extend(["--trusted-host", host])
|
||||
if finder.allow_all_prereleases:
|
||||
args.append('--pre')
|
||||
args.append("--pre")
|
||||
if finder.process_dependency_links:
|
||||
args.append('--process-dependency-links')
|
||||
args.append('--')
|
||||
args.append("--process-dependency-links")
|
||||
args.append("--")
|
||||
args.extend(requirements)
|
||||
out, _ = vistir.misc.run(args, return_object=False, nospin=True, block=True,
|
||||
combine_stderr=False)
|
||||
out, _ = vistir.misc.run(
|
||||
args, return_object=False, nospin=True, block=True, combine_stderr=False
|
||||
)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def uninstall(self, pkgname, *args, **kwargs):
|
||||
@@ -983,18 +1084,21 @@ class Environment:
|
||||
auto_confirm = kwargs.pop("auto_confirm", True)
|
||||
verbose = kwargs.pop("verbose", False)
|
||||
with self.activated():
|
||||
monkey_patch = next(iter(
|
||||
dist for dist in self.base_working_set
|
||||
monkey_patch = next(
|
||||
iter(
|
||||
dist
|
||||
for dist in self.base_working_set
|
||||
if dist.project_name == "recursive-monkey-patch"
|
||||
), None)
|
||||
),
|
||||
None,
|
||||
)
|
||||
if monkey_patch:
|
||||
monkey_patch.activate()
|
||||
pip_shims = self.safe_import("pip_shims")
|
||||
pathset_base = pip_shims.UninstallPathSet
|
||||
pathset_base._permitted = PatchedUninstaller._permitted
|
||||
dist = next(
|
||||
iter(d for d in self.get_working_set() if d.project_name == pkgname),
|
||||
None
|
||||
iter(d for d in self.get_working_set() if d.project_name == pkgname), None
|
||||
)
|
||||
pathset = pathset_base.from_dist(dist)
|
||||
if pathset is not None:
|
||||
|
||||
+20
-19
@@ -10,7 +10,6 @@ from vistir.path import normalize_drive
|
||||
from pipenv._compat import fix_utf8
|
||||
from pipenv.vendor.vistir.misc import _isatty, 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")
|
||||
@@ -36,8 +35,7 @@ def env_to_bool(val):
|
||||
|
||||
|
||||
def _is_env_truthy(name):
|
||||
"""An environment variable is truthy if it exists and isn't one of (0, false, no, off)
|
||||
"""
|
||||
"""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 _false_values
|
||||
@@ -86,8 +84,8 @@ def normalize_pipfile_path(p):
|
||||
except OSError:
|
||||
loc = loc.absolute()
|
||||
# Recase the path properly on Windows. From https://stackoverflow.com/a/35229734/5043728
|
||||
if os.name == 'nt':
|
||||
matches = glob.glob(re.sub(r'([^:/\\])(?=[/\\]|$)', r'[\1]', str(loc)))
|
||||
if os.name == "nt":
|
||||
matches = glob.glob(re.sub(r"([^:/\\])(?=[/\\]|$)", r"[\1]", str(loc)))
|
||||
path_str = matches and matches[0] or str(loc)
|
||||
else:
|
||||
path_str = str(loc)
|
||||
@@ -99,7 +97,7 @@ def normalize_pipfile_path(p):
|
||||
os.environ.pop("__PYVENV_LAUNCHER__", None)
|
||||
# Internal, to tell whether the command line session is interactive.
|
||||
SESSION_IS_INTERACTIVE = _isatty(sys.stdout)
|
||||
PIPENV_IS_CI = env_to_bool(os.environ.get('CI') or os.environ.get('TF_BUILD') or False)
|
||||
PIPENV_IS_CI = env_to_bool(os.environ.get("CI") or os.environ.get("TF_BUILD") or False)
|
||||
PIPENV_COLORBLIND = bool(os.environ.get("PIPENV_COLORBLIND"))
|
||||
"""If set, disable terminal colors.
|
||||
|
||||
@@ -125,14 +123,18 @@ class Setting:
|
||||
|
||||
def initialize(self):
|
||||
|
||||
self.PIPENV_CACHE_DIR = os.environ.get("PIPENV_CACHE_DIR", user_cache_dir("pipenv"))
|
||||
self.PIPENV_CACHE_DIR = os.environ.get(
|
||||
"PIPENV_CACHE_DIR", user_cache_dir("pipenv")
|
||||
)
|
||||
"""Location for Pipenv to store it's package cache.
|
||||
|
||||
Default is to use appdir's user cache directory.
|
||||
"""
|
||||
|
||||
# Tells Pipenv which Python to default to, when none is provided.
|
||||
self.PIPENV_DEFAULT_PYTHON_VERSION = os.environ.get("PIPENV_DEFAULT_PYTHON_VERSION")
|
||||
self.PIPENV_DEFAULT_PYTHON_VERSION = os.environ.get(
|
||||
"PIPENV_DEFAULT_PYTHON_VERSION"
|
||||
)
|
||||
"""Use this Python version when creating new virtual environments by default.
|
||||
|
||||
This can be set to a version string, e.g. ``3.9``, or a path. Default is to use
|
||||
@@ -180,7 +182,9 @@ class Setting:
|
||||
and enables the user to use any user-built environments with Pipenv.
|
||||
"""
|
||||
|
||||
self.PIPENV_INSTALL_TIMEOUT = int(os.environ.get("PIPENV_INSTALL_TIMEOUT", 60 * 15))
|
||||
self.PIPENV_INSTALL_TIMEOUT = int(
|
||||
os.environ.get("PIPENV_INSTALL_TIMEOUT", 60 * 15)
|
||||
)
|
||||
"""Max number of seconds to wait for package installation.
|
||||
|
||||
Defaults to 900 (15 minutes), a very long arbitrary time.
|
||||
@@ -248,7 +252,7 @@ class Setting:
|
||||
pipenv_pipfile = normalize_pipfile_path(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
|
||||
os.environ["PIPENV_PIPFILE"] = pipenv_pipfile
|
||||
self.PIPENV_PIPFILE = pipenv_pipfile
|
||||
"""If set, this specifies a custom Pipfile location.
|
||||
|
||||
@@ -332,10 +336,9 @@ class Setting:
|
||||
Defaults to ``(w)ipe``
|
||||
"""
|
||||
|
||||
self.PIPENV_RESOLVE_VCS = (
|
||||
os.environ.get("PIPENV_RESOLVE_VCS") is None
|
||||
or _is_env_truthy("PIPENV_RESOLVE_VCS")
|
||||
)
|
||||
self.PIPENV_RESOLVE_VCS = os.environ.get(
|
||||
"PIPENV_RESOLVE_VCS"
|
||||
) is None or _is_env_truthy("PIPENV_RESOLVE_VCS")
|
||||
|
||||
"""Tells Pipenv whether to resolve all VCS dependencies in full.
|
||||
|
||||
@@ -344,9 +347,7 @@ class Setting:
|
||||
approach, you may set this to '0', 'off', or 'false'.
|
||||
"""
|
||||
|
||||
self.PIPENV_PYUP_API_KEY = os.environ.get(
|
||||
"PIPENV_PYUP_API_KEY", None
|
||||
)
|
||||
self.PIPENV_PYUP_API_KEY = os.environ.get("PIPENV_PYUP_API_KEY", None)
|
||||
|
||||
# Internal, support running in a different Python from sys.executable.
|
||||
self.PIPENV_PYTHON = os.environ.get("PIPENV_PYTHON")
|
||||
@@ -396,12 +397,12 @@ class Setting:
|
||||
def is_using_venv():
|
||||
# type: () -> bool
|
||||
"""Check for venv-based virtual environment which sets sys.base_prefix"""
|
||||
if getattr(sys, 'real_prefix', None) is not None:
|
||||
if getattr(sys, "real_prefix", None) is not None:
|
||||
# virtualenv venvs
|
||||
result = True
|
||||
else:
|
||||
# PEP 405 venvs
|
||||
result = sys.prefix != getattr(sys, 'base_prefix', sys.prefix)
|
||||
result = sys.prefix != getattr(sys, "base_prefix", sys.prefix)
|
||||
return result
|
||||
|
||||
|
||||
|
||||
+82
-70
@@ -1,30 +1,29 @@
|
||||
import itertools
|
||||
import re
|
||||
import sys
|
||||
|
||||
from collections import namedtuple
|
||||
from traceback import format_tb
|
||||
|
||||
from pipenv import environments
|
||||
from pipenv._compat import decode_for_output
|
||||
from pipenv.patched import crayons
|
||||
from pipenv.vendor.click.exceptions import (
|
||||
ClickException, FileError, UsageError
|
||||
)
|
||||
from pipenv.vendor.vistir.misc import echo as click_echo
|
||||
from pipenv.vendor import vistir
|
||||
from pipenv.vendor.click.exceptions import ClickException, FileError, UsageError
|
||||
from pipenv.vendor.vistir.misc import echo as click_echo
|
||||
|
||||
ANSI_REMOVAL_RE = re.compile(r"\033\[((?:\d|;)*)([a-zA-Z])", re.MULTILINE)
|
||||
STRING_TYPES = ((str,), crayons.ColoredString)
|
||||
|
||||
if sys.version_info[:2] >= (3, 7):
|
||||
KnownException = namedtuple(
|
||||
'KnownException', ['exception_name', 'match_string', 'show_from_string', 'prefix'],
|
||||
defaults=[None, None, None, ""]
|
||||
"KnownException",
|
||||
["exception_name", "match_string", "show_from_string", "prefix"],
|
||||
defaults=[None, None, None, ""],
|
||||
)
|
||||
else:
|
||||
KnownException = namedtuple(
|
||||
'KnownException', ['exception_name', 'match_string', 'show_from_string', 'prefix'],
|
||||
"KnownException",
|
||||
["exception_name", "match_string", "show_from_string", "prefix"],
|
||||
)
|
||||
KnownException.__new__.__defaults__ = (None, None, None, "")
|
||||
|
||||
@@ -33,8 +32,8 @@ KNOWN_EXCEPTIONS = [
|
||||
KnownException(
|
||||
"VirtualenvCreationException",
|
||||
match_string="do_create_virtualenv",
|
||||
show_from_string=None
|
||||
)
|
||||
show_from_string=None,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -51,9 +50,7 @@ def handle_exception(exc_type, exception, traceback, hook=sys.excepthook):
|
||||
line = f" {line}"
|
||||
else:
|
||||
line = f" {line}"
|
||||
line = "[{!s}]: {}".format(
|
||||
exception.__class__.__name__, line
|
||||
)
|
||||
line = "[{!s}]: {}".format(exception.__class__.__name__, line)
|
||||
formatted_lines.append(line)
|
||||
# use new exception prettification rules to format exceptions according to
|
||||
# UX rules
|
||||
@@ -102,20 +99,27 @@ class PipenvCmdError(PipenvException):
|
||||
def show(self, file=None):
|
||||
if file is None:
|
||||
file = vistir.misc.get_text_stderr()
|
||||
click_echo("{} {}".format(
|
||||
click_echo(
|
||||
"{} {}".format(
|
||||
crayons.red("Error running command: "),
|
||||
crayons.normal(decode_for_output(f"$ {self.cmd}", file), bold=True)
|
||||
), err=True)
|
||||
crayons.normal(decode_for_output(f"$ {self.cmd}", file), bold=True),
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
if self.out:
|
||||
click_echo("{} {}".format(
|
||||
crayons.normal("OUTPUT: "),
|
||||
decode_for_output(self.out, file)
|
||||
), err=True)
|
||||
click_echo(
|
||||
"{} {}".format(
|
||||
crayons.normal("OUTPUT: "), decode_for_output(self.out, file)
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
if self.err:
|
||||
click_echo("{} {}".format(
|
||||
crayons.normal("STDERR: "),
|
||||
decode_for_output(self.err, file)
|
||||
), err=True)
|
||||
click_echo(
|
||||
"{} {}".format(
|
||||
crayons.normal("STDERR: "), decode_for_output(self.err, file)
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
|
||||
|
||||
class JSONParseError(PipenvException):
|
||||
@@ -128,18 +132,20 @@ class JSONParseError(PipenvException):
|
||||
file = vistir.misc.get_text_stderr()
|
||||
message = "{}\n{}".format(
|
||||
crayons.normal("Failed parsing JSON results:", bold=True),
|
||||
decode_for_output(self.message.strip(), file)
|
||||
decode_for_output(self.message.strip(), file),
|
||||
)
|
||||
click_echo(message, err=True)
|
||||
if self.error_text:
|
||||
click_echo("{} {}".format(
|
||||
click_echo(
|
||||
"{} {}".format(
|
||||
crayons.normal("ERROR TEXT:", bold=True),
|
||||
decode_for_output(self.error_text, file)
|
||||
), err=True)
|
||||
decode_for_output(self.error_text, file),
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
|
||||
|
||||
class PipenvUsageError(UsageError):
|
||||
|
||||
def __init__(self, message=None, ctx=None, **kwargs):
|
||||
formatted_message = "{0}: {1}"
|
||||
msg_prefix = crayons.red("ERROR:", bold=True)
|
||||
@@ -164,29 +170,30 @@ class PipenvUsageError(UsageError):
|
||||
if color:
|
||||
extra = getattr(crayons, color, "blue")(extra)
|
||||
click_echo(decode_for_output(extra, file), file=file)
|
||||
hint = ''
|
||||
hint = ""
|
||||
if self.cmd is not None and self.cmd.get_help_option(self.ctx) is not None:
|
||||
hint = ('Try "%s %s" for help.\n'
|
||||
% (self.ctx.command_path, self.ctx.help_option_names[0]))
|
||||
hint = 'Try "%s %s" for help.\n' % (
|
||||
self.ctx.command_path,
|
||||
self.ctx.help_option_names[0],
|
||||
)
|
||||
if self.ctx is not None:
|
||||
click_echo(self.ctx.get_usage() + '\n%s' % hint, file=file, color=color)
|
||||
click_echo(self.ctx.get_usage() + "\n%s" % hint, file=file, color=color)
|
||||
click_echo(self.message, file=file)
|
||||
|
||||
|
||||
class PipenvFileError(FileError):
|
||||
formatted_message = "{0} {{0}} {{1}}".format(
|
||||
crayons.red("ERROR:", bold=True)
|
||||
)
|
||||
formatted_message = "{0} {{0}} {{1}}".format(crayons.red("ERROR:", bold=True))
|
||||
|
||||
def __init__(self, filename, message=None, **kwargs):
|
||||
extra = kwargs.pop("extra", [])
|
||||
if not message:
|
||||
message = crayons.normal("Please ensure that the file exists!", bold=True)
|
||||
message = self.formatted_message.format(
|
||||
crayons.normal(f"{filename} not found!", bold=True),
|
||||
message
|
||||
crayons.normal(f"{filename} not found!", bold=True), message
|
||||
)
|
||||
FileError.__init__(
|
||||
self, filename=filename, hint=decode_for_output(message), **kwargs
|
||||
)
|
||||
FileError.__init__(self, filename=filename, hint=decode_for_output(message), **kwargs)
|
||||
self.extra = extra
|
||||
|
||||
def show(self, file=None):
|
||||
@@ -203,14 +210,13 @@ class PipenvFileError(FileError):
|
||||
class PipfileNotFound(PipenvFileError):
|
||||
def __init__(self, filename="Pipfile", extra=None, **kwargs):
|
||||
extra = kwargs.pop("extra", [])
|
||||
message = (
|
||||
"{} {}".format(
|
||||
message = "{} {}".format(
|
||||
crayons.red("Aborting!", bold=True),
|
||||
crayons.normal(
|
||||
"Please ensure that the file exists and is located in your"
|
||||
" project root directory.", bold=True
|
||||
)
|
||||
)
|
||||
" project root directory.",
|
||||
bold=True,
|
||||
),
|
||||
)
|
||||
super().__init__(filename, message=message, extra=extra, **kwargs)
|
||||
|
||||
@@ -221,7 +227,7 @@ class LockfileNotFound(PipenvFileError):
|
||||
message = "{} {} {}".format(
|
||||
crayons.normal("You need to run", bold=True),
|
||||
crayons.red("$ pipenv lock", bold=True),
|
||||
crayons.normal("before you can continue.", bold=True)
|
||||
crayons.normal("before you can continue.", bold=True),
|
||||
)
|
||||
super().__init__(filename, message=message, extra=extra, **kwargs)
|
||||
|
||||
@@ -264,7 +270,6 @@ class SetupException(PipenvException):
|
||||
|
||||
|
||||
class VirtualenvException(PipenvException):
|
||||
|
||||
def __init__(self, message=None, **kwargs):
|
||||
if not message:
|
||||
message = (
|
||||
@@ -309,7 +314,7 @@ class UninstallError(PipenvException):
|
||||
extra = [
|
||||
"{} {}".format(
|
||||
crayons.cyan("Attempted to run command: "),
|
||||
crayons.yellow(f"$ {command!r}", bold=True)
|
||||
crayons.yellow(f"$ {command!r}", bold=True),
|
||||
)
|
||||
]
|
||||
extra.extend([crayons.cyan(line.strip()) for line in return_values.splitlines()])
|
||||
@@ -317,7 +322,7 @@ class UninstallError(PipenvException):
|
||||
package = " ".join(package)
|
||||
message = "{!s} {!s}...".format(
|
||||
crayons.normal("Failed to uninstall package(s)"),
|
||||
crayons.yellow(f"{package}!s", bold=True)
|
||||
crayons.yellow(f"{package}!s", bold=True),
|
||||
)
|
||||
self.exit_code = return_code
|
||||
PipenvException.__init__(self, message=message, extra=extra)
|
||||
@@ -332,8 +337,7 @@ class InstallError(PipenvException):
|
||||
crayons.normal(f"{package!s}", bold=True)
|
||||
)
|
||||
message = "{} {}".format(
|
||||
f"{package_message}",
|
||||
crayons.yellow("Package installation failed...")
|
||||
f"{package_message}", crayons.yellow("Package installation failed...")
|
||||
)
|
||||
extra = kwargs.pop("extra", [])
|
||||
PipenvException.__init__(self, message=message, extra=extra, **kwargs)
|
||||
@@ -344,17 +348,21 @@ class CacheError(PipenvException):
|
||||
message = "{} {}\n{}".format(
|
||||
crayons.cyan("Corrupt cache file"),
|
||||
crayons.normal(f"{path!s}"),
|
||||
crayons.normal('Consider trying "pipenv lock --clear" to clear the cache.')
|
||||
crayons.normal('Consider trying "pipenv lock --clear" to clear the cache.'),
|
||||
)
|
||||
PipenvException.__init__(self, message=message)
|
||||
|
||||
|
||||
class DependencyConflict(PipenvException):
|
||||
def __init__(self, message):
|
||||
extra = ["{} {}".format(
|
||||
extra = [
|
||||
"{} {}".format(
|
||||
crayons.red("The operation failed...", bold=True),
|
||||
crayons.red("A dependency conflict was detected and could not be resolved."),
|
||||
)]
|
||||
crayons.red(
|
||||
"A dependency conflict was detected and could not be resolved."
|
||||
),
|
||||
)
|
||||
]
|
||||
PipenvException.__init__(self, message, extra=extra)
|
||||
|
||||
|
||||
@@ -382,21 +390,28 @@ class ResolutionFailure(PipenvException):
|
||||
crayons.cyan(
|
||||
"Please check your version specifier and version number. "
|
||||
"See PEP440 for more information."
|
||||
)
|
||||
),
|
||||
)
|
||||
PipenvException.__init__(self, message, extra=extra)
|
||||
|
||||
|
||||
class RequirementError(PipenvException):
|
||||
|
||||
def __init__(self, req=None):
|
||||
from .utils import VCS_LIST
|
||||
keys = ("name", "path",) + VCS_LIST + ("line", "uri", "url", "relpath")
|
||||
|
||||
keys = (
|
||||
(
|
||||
"name",
|
||||
"path",
|
||||
)
|
||||
+ VCS_LIST
|
||||
+ ("line", "uri", "url", "relpath")
|
||||
)
|
||||
if req is not None:
|
||||
possible_display_values = [getattr(req, value, None) for value in keys]
|
||||
req_value = next(iter(
|
||||
val for val in possible_display_values if val is not None
|
||||
), None)
|
||||
req_value = next(
|
||||
iter(val for val in possible_display_values if val is not None), None
|
||||
)
|
||||
if not req_value:
|
||||
getstate_fn = getattr(req, "__getstate__", None)
|
||||
slots = getattr(req, "__slots__", None)
|
||||
@@ -405,22 +420,17 @@ class RequirementError(PipenvException):
|
||||
req_value = getstate_fn()
|
||||
elif slots:
|
||||
slot_vals = [
|
||||
(k, getattr(req, k, None)) for k in slots
|
||||
if getattr(req, k, None)
|
||||
(k, getattr(req, k, None)) for k in slots if getattr(req, k, None)
|
||||
]
|
||||
req_value = "\n".join([
|
||||
f" {k}: {v}" for k, v in slot_vals
|
||||
])
|
||||
req_value = "\n".join([f" {k}: {v}" for k, v in slot_vals])
|
||||
elif keys_fn:
|
||||
values = [(k, req.get(k)) for k in keys_fn() if req.get(k)]
|
||||
req_value = "\n".join([
|
||||
f" {k}: {v}" for k, v in values
|
||||
])
|
||||
req_value = "\n".join([f" {k}: {v}" for k, v in values])
|
||||
else:
|
||||
req_value = getattr(req.line_instance, "line", None)
|
||||
message = "{} {}".format(
|
||||
crayons.normal(decode_for_output("Failed creating requirement instance")),
|
||||
crayons.normal(decode_for_output(f"{req_value!r}"))
|
||||
crayons.normal(decode_for_output(f"{req_value!r}")),
|
||||
)
|
||||
extra = [str(req)]
|
||||
PipenvException.__init__(self, message, extra=extra)
|
||||
@@ -432,7 +442,9 @@ def prettify_exc(error):
|
||||
errors = []
|
||||
for exc in KNOWN_EXCEPTIONS:
|
||||
search_string = exc.match_string if exc.match_string else exc.exception_name
|
||||
split_string = exc.show_from_string if exc.show_from_string else exc.exception_name
|
||||
split_string = (
|
||||
exc.show_from_string if exc.show_from_string else exc.exception_name
|
||||
)
|
||||
if search_string in error:
|
||||
# for known exceptions with no display rules and no prefix
|
||||
# we should simply show nothing
|
||||
|
||||
+2
-4
@@ -3,7 +3,6 @@ import pprint
|
||||
import sys
|
||||
|
||||
import pipenv
|
||||
|
||||
from pipenv.pep508checker import lookup
|
||||
from pipenv.vendor import pythonfinder
|
||||
|
||||
@@ -69,9 +68,7 @@ def get_pipenv_diagnostics(project):
|
||||
print("")
|
||||
if project.lockfile_exists:
|
||||
print("")
|
||||
print_utf(
|
||||
f"Contents of `Pipfile.lock` ({project.lockfile_location!r}):"
|
||||
)
|
||||
print_utf(f"Contents of `Pipfile.lock` ({project.lockfile_location!r}):")
|
||||
print("")
|
||||
print("```json")
|
||||
with open(project.lockfile_location) as f:
|
||||
@@ -82,4 +79,5 @@ def get_pipenv_diagnostics(project):
|
||||
|
||||
if __name__ == "__main__":
|
||||
from pipenv.project import Project
|
||||
|
||||
get_pipenv_diagnostics(Project())
|
||||
|
||||
+39
-35
@@ -1,12 +1,12 @@
|
||||
import os
|
||||
import operator
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
from pipenv.vendor import attr
|
||||
from pipenv.utils.processes import subprocess_run
|
||||
from pipenv.utils.shell import find_windows_executable
|
||||
from pipenv.vendor import attr
|
||||
|
||||
|
||||
@attr.s
|
||||
@@ -20,15 +20,14 @@ class Version:
|
||||
parts = [self.major, self.minor]
|
||||
if self.patch is not None:
|
||||
parts.append(self.patch)
|
||||
return '.'.join(str(p) for p in parts)
|
||||
return ".".join(str(p) for p in parts)
|
||||
|
||||
@classmethod
|
||||
def parse(cls, name):
|
||||
"""Parse an X.Y.Z or X.Y string into a version tuple.
|
||||
"""
|
||||
match = re.match(r'^(\d+)\.(\d+)(?:\.(\d+))?$', name)
|
||||
"""Parse an X.Y.Z or X.Y string into a version tuple."""
|
||||
match = re.match(r"^(\d+)\.(\d+)(?:\.(\d+))?$", name)
|
||||
if not match:
|
||||
raise ValueError(f'invalid version name {name!r}')
|
||||
raise ValueError(f"invalid version name {name!r}")
|
||||
major = int(match.group(1))
|
||||
minor = int(match.group(2))
|
||||
patch = match.group(3)
|
||||
@@ -47,8 +46,7 @@ class Version:
|
||||
return (self.major, self.minor, self.patch or 0)
|
||||
|
||||
def matches_minor(self, other):
|
||||
"""Check whether this version matches the other in (major, minor).
|
||||
"""
|
||||
"""Check whether this version matches the other in (major, minor)."""
|
||||
return (self.major, self.minor) == (other.major, other.minor)
|
||||
|
||||
|
||||
@@ -64,7 +62,6 @@ class InstallerError(RuntimeError):
|
||||
|
||||
|
||||
class Installer(metaclass=ABCMeta):
|
||||
|
||||
def __init__(self, project):
|
||||
self.cmd = self._find_installer()
|
||||
self.project = project
|
||||
@@ -103,32 +100,37 @@ class Installer(metaclass=ABCMeta):
|
||||
# Look for the Python installer using the equivalent of 'which'. On
|
||||
# Homebrew-installed systems, the env var may not be set, but this
|
||||
# strategy will work.
|
||||
find_windows_executable('', name),
|
||||
find_windows_executable("", name),
|
||||
# Check for explicitly set install locations (e.g. PYENV_ROOT, ASDF_DIR).
|
||||
os.path.join(os.path.expanduser(os.getenv(env_var, '/dev/null')), 'bin', name),
|
||||
os.path.join(
|
||||
os.path.expanduser(os.getenv(env_var, "/dev/null")), "bin", name
|
||||
),
|
||||
# Check the pyenv/asdf-recommended from-source install locations
|
||||
os.path.join(os.path.expanduser(f'~/.{name}'), 'bin', name),
|
||||
os.path.join(os.path.expanduser(f"~/.{name}"), "bin", name),
|
||||
):
|
||||
if (
|
||||
candidate is not None
|
||||
and os.path.isfile(candidate)
|
||||
and os.access(candidate, os.X_OK)
|
||||
):
|
||||
if candidate is not None and os.path.isfile(candidate) and os.access(candidate, os.X_OK):
|
||||
return candidate
|
||||
raise InstallerNotFound()
|
||||
|
||||
def _run(self, *args, **kwargs):
|
||||
timeout = kwargs.pop('timeout', 30)
|
||||
shell = kwargs.pop('shell', False)
|
||||
timeout = kwargs.pop("timeout", 30)
|
||||
shell = kwargs.pop("shell", False)
|
||||
if kwargs:
|
||||
k = list(kwargs.keys())[0]
|
||||
raise TypeError(f'unexpected keyword argument {k!r}')
|
||||
raise TypeError(f"unexpected keyword argument {k!r}")
|
||||
args = (self.cmd,) + tuple(args)
|
||||
c = subprocess_run(args, timeout=timeout, shell=shell)
|
||||
if c.returncode != 0:
|
||||
raise InstallerError(f'failed to run {args}', c)
|
||||
raise InstallerError(f"failed to run {args}", c)
|
||||
return c
|
||||
|
||||
@abstractmethod
|
||||
def iter_installable_versions(self):
|
||||
"""Iterate through CPython versions available for Pipenv to install.
|
||||
"""
|
||||
"""Iterate through CPython versions available for Pipenv to install."""
|
||||
pass
|
||||
|
||||
def find_version_to_install(self, name):
|
||||
@@ -140,14 +142,17 @@ class Installer(metaclass=ABCMeta):
|
||||
if version.patch is not None:
|
||||
return name
|
||||
try:
|
||||
best_match = max((
|
||||
best_match = max(
|
||||
(
|
||||
inst_version
|
||||
for inst_version in self.iter_installable_versions()
|
||||
if inst_version.matches_minor(version)
|
||||
), key=operator.attrgetter('cmpkey'))
|
||||
),
|
||||
key=operator.attrgetter("cmpkey"),
|
||||
)
|
||||
except ValueError:
|
||||
raise ValueError(
|
||||
f'no installable version found for {name!r}',
|
||||
f"no installable version found for {name!r}",
|
||||
)
|
||||
return best_match
|
||||
|
||||
@@ -168,17 +173,16 @@ class Pyenv(Installer):
|
||||
WIN = sys.platform.startswith("win") or (sys.platform == "cli" and os.name == "nt")
|
||||
|
||||
def _find_installer(self):
|
||||
return self._find_python_installer_by_name_and_env('pyenv', 'PYENV_ROOT')
|
||||
return self._find_python_installer_by_name_and_env("pyenv", "PYENV_ROOT")
|
||||
|
||||
def _run(self, *args, **kwargs):
|
||||
if Pyenv.WIN:
|
||||
kwargs['shell'] = True
|
||||
kwargs["shell"] = True
|
||||
return super(Pyenv, self)._run(*args, **kwargs)
|
||||
|
||||
def iter_installable_versions(self):
|
||||
"""Iterate through CPython versions available for Pipenv to install.
|
||||
"""
|
||||
for name in self._run('install', '--list').stdout.splitlines():
|
||||
"""Iterate through CPython versions available for Pipenv to install."""
|
||||
for name in self._run("install", "--list").stdout.splitlines():
|
||||
try:
|
||||
version = Version.parse(name.strip())
|
||||
except ValueError:
|
||||
@@ -192,7 +196,7 @@ class Pyenv(Installer):
|
||||
A ValueError is raised if the given version does not have a match in
|
||||
pyenv. A InstallerError is raised if the pyenv command fails.
|
||||
"""
|
||||
args = ['install', '-s', str(version)]
|
||||
args = ["install", "-s", str(version)]
|
||||
if Pyenv.WIN:
|
||||
# pyenv-win skips installed versions by default and does not support -s
|
||||
del args[1]
|
||||
@@ -200,14 +204,12 @@ class Pyenv(Installer):
|
||||
|
||||
|
||||
class Asdf(Installer):
|
||||
|
||||
def _find_installer(self):
|
||||
return self._find_python_installer_by_name_and_env('asdf', 'ASDF_DIR')
|
||||
return self._find_python_installer_by_name_and_env("asdf", "ASDF_DIR")
|
||||
|
||||
def iter_installable_versions(self):
|
||||
"""Iterate through CPython versions available for asdf to install.
|
||||
"""
|
||||
for name in self._run('list-all', 'python').stdout.splitlines():
|
||||
"""Iterate through CPython versions available for asdf to install."""
|
||||
for name in self._run("list-all", "python").stdout.splitlines():
|
||||
try:
|
||||
version = Version.parse(name.strip())
|
||||
except ValueError:
|
||||
@@ -222,7 +224,9 @@ class Asdf(Installer):
|
||||
asdf. A InstallerError is raised if the asdf command fails.
|
||||
"""
|
||||
c = self._run(
|
||||
'install', 'python', str(version),
|
||||
"install",
|
||||
"python",
|
||||
str(version),
|
||||
timeout=self.project.s.PIPENV_INSTALL_TIMEOUT,
|
||||
)
|
||||
return c
|
||||
|
||||
+15
-5
@@ -11,18 +11,28 @@ class PopenProcess:
|
||||
"""A wrapper of subprocess.Popen that
|
||||
doesn't need to worry about the Pipe buffer exceeding the limit.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, args, *, block=True, encoding=DEFAULT_ENCODING, env=None, timeout=None, **other_kwargs
|
||||
self,
|
||||
args,
|
||||
*,
|
||||
block=True,
|
||||
encoding=DEFAULT_ENCODING,
|
||||
env=None,
|
||||
timeout=None,
|
||||
**other_kwargs
|
||||
):
|
||||
self.blocking = block
|
||||
self.env = env
|
||||
self.script = Script.parse(args)
|
||||
if env is not None:
|
||||
env = dict(os.environ, **env)
|
||||
other_kwargs['env'] = env
|
||||
other_kwargs['stdout'] = subprocess.PIPE
|
||||
other_kwargs['stderr'] = subprocess.PIPE
|
||||
self._process = subprocess.Popen(args, universal_newlines=True, encoding=encoding, **other_kwargs)
|
||||
other_kwargs["env"] = env
|
||||
other_kwargs["stdout"] = subprocess.PIPE
|
||||
other_kwargs["stderr"] = subprocess.PIPE
|
||||
self._process = subprocess.Popen(
|
||||
args, universal_newlines=True, encoding=encoding, **other_kwargs
|
||||
)
|
||||
self._endtime = None
|
||||
if timeout is not None:
|
||||
self._endtime = _time() + timeout
|
||||
|
||||
@@ -15,7 +15,6 @@ import crayons
|
||||
|
||||
from pipenv.environments import PIPENV_COLORBLIND, PIPENV_HIDE_EMOJIS
|
||||
|
||||
|
||||
STREAM = sys.stderr
|
||||
MILL_TEMPLATE = "%s %s %i/%i\r"
|
||||
DOTS_CHAR = "."
|
||||
|
||||
+85
-67
@@ -6,10 +6,10 @@ import io
|
||||
import json
|
||||
import operator
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
import urllib.parse
|
||||
from pathlib import Path
|
||||
|
||||
import pipfile
|
||||
import pipfile.api
|
||||
@@ -20,11 +20,21 @@ import vistir
|
||||
from pipenv.cmdparse import Script
|
||||
from pipenv.core import system_which
|
||||
from pipenv.environment import Environment
|
||||
from pipenv.environments import Setting, is_type_checking, is_in_virtualenv, normalize_pipfile_path
|
||||
from pipenv.utils.dependencies import get_canonical_names, is_editable, is_installable_file, is_star, python_version
|
||||
from pipenv.environments import (
|
||||
Setting,
|
||||
is_in_virtualenv,
|
||||
is_type_checking,
|
||||
normalize_pipfile_path,
|
||||
)
|
||||
from pipenv.utils.dependencies import (
|
||||
get_canonical_names,
|
||||
is_editable,
|
||||
is_installable_file,
|
||||
is_star,
|
||||
python_version,
|
||||
)
|
||||
from pipenv.utils.internet import get_url_name, is_valid_url, proper_case
|
||||
from pipenv.utils.resolver import pep423_name
|
||||
from pipenv.utils.toml import cleanup_toml, convert_toml_outline_tables
|
||||
from pipenv.utils.shell import (
|
||||
find_requirements,
|
||||
find_windows_executable,
|
||||
@@ -32,19 +42,17 @@ from pipenv.utils.shell import (
|
||||
get_workon_home,
|
||||
is_virtual_environment,
|
||||
looks_like_dir,
|
||||
safe_expandvars
|
||||
safe_expandvars,
|
||||
)
|
||||
|
||||
from pipenv.utils.toml import cleanup_toml, convert_toml_outline_tables
|
||||
from pipenv.vendor.cached_property import cached_property
|
||||
from pipenv.vendor.requirementslib.models.utils import (
|
||||
get_default_pyproject_backend
|
||||
)
|
||||
|
||||
from pipenv.vendor.requirementslib.models.utils import get_default_pyproject_backend
|
||||
|
||||
if is_type_checking():
|
||||
from typing import Dict, List, Optional, Set, Text, Tuple, Union
|
||||
|
||||
import pkg_resources
|
||||
|
||||
TSource = Dict[Text, Union[Text, bool]]
|
||||
TPackageEntry = Dict[str, Union[bool, str, List[str]]]
|
||||
TPackage = Dict[str, TPackageEntry]
|
||||
@@ -114,22 +122,20 @@ class Project:
|
||||
self._requirements_location = None
|
||||
self._original_dir = os.path.abspath(os.curdir)
|
||||
self._environment = None
|
||||
self._build_system = {
|
||||
"requires": ["setuptools", "wheel"]
|
||||
}
|
||||
self._build_system = {"requires": ["setuptools", "wheel"]}
|
||||
self.python_version = python_version
|
||||
self.s = Setting()
|
||||
if self.s.PIPENV_TEST_INDEX:
|
||||
self.default_source = {
|
||||
u"url": self.s.PIPENV_TEST_INDEX,
|
||||
u"verify_ssl": True,
|
||||
u"name": u"custom",
|
||||
"url": self.s.PIPENV_TEST_INDEX,
|
||||
"verify_ssl": True,
|
||||
"name": "custom",
|
||||
}
|
||||
else:
|
||||
self.default_source = {
|
||||
u"url": u"https://pypi.org/simple",
|
||||
u"verify_ssl": True,
|
||||
u"name": u"pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": True,
|
||||
"name": "pypi",
|
||||
}
|
||||
pipfile.api.DEFAULT_SOURCE = self.default_source
|
||||
|
||||
@@ -151,6 +157,7 @@ class Project:
|
||||
def _build_package_list(self, package_section):
|
||||
"""Returns a list of packages for pip-tools to consume."""
|
||||
from pipenv.vendor.requirementslib.utils import is_vcs
|
||||
|
||||
ps = {}
|
||||
# TODO: Separate the logic for showing packages from the filters for supplying pip-tools
|
||||
for k, v in self.parsed_pipfile.get(package_section, {}).items():
|
||||
@@ -217,9 +224,7 @@ class Project:
|
||||
def required_python_version(self):
|
||||
# type: () -> str
|
||||
if self.pipfile_exists:
|
||||
required = self.parsed_pipfile.get("requires", {}).get(
|
||||
"python_full_version"
|
||||
)
|
||||
required = self.parsed_pipfile.get("requires", {}).get("python_full_version")
|
||||
if not required:
|
||||
required = self.parsed_pipfile.get("requires", {}).get("python_version")
|
||||
if required != "*":
|
||||
@@ -293,8 +298,10 @@ class Project:
|
||||
def working_set(self):
|
||||
# type: () -> pkg_resources.WorkingSet
|
||||
from pipenv.utils.shell import load_path
|
||||
|
||||
sys_path = load_path(self.which("python"))
|
||||
import pkg_resources
|
||||
|
||||
return pkg_resources.WorkingSet(sys_path)
|
||||
|
||||
@property
|
||||
@@ -314,7 +321,7 @@ class Project:
|
||||
return {
|
||||
"dev": dev_keys,
|
||||
"default": default_keys,
|
||||
"combined": dev_keys | default_keys
|
||||
"combined": dev_keys | default_keys,
|
||||
}
|
||||
|
||||
@property
|
||||
@@ -325,7 +332,7 @@ class Project:
|
||||
return {
|
||||
"dev": dev_keys,
|
||||
"default": default_keys,
|
||||
"combined": dev_keys | default_keys
|
||||
"combined": dev_keys | default_keys,
|
||||
}
|
||||
|
||||
def get_environment(self, allow_global=False):
|
||||
@@ -339,8 +346,12 @@ class Project:
|
||||
python = None
|
||||
sources = self.sources if self.sources else [self.default_source]
|
||||
environment = Environment(
|
||||
prefix=prefix, python=python, is_venv=is_venv, sources=sources,
|
||||
pipfile=self.parsed_pipfile, project=self
|
||||
prefix=prefix,
|
||||
python=python,
|
||||
is_venv=is_venv,
|
||||
sources=sources,
|
||||
pipfile=self.parsed_pipfile,
|
||||
project=self,
|
||||
)
|
||||
pipenv_dist = get_pipenv_dist(pkg="pipenv")
|
||||
if pipenv_dist:
|
||||
@@ -442,7 +453,8 @@ class Project:
|
||||
virtualenv_env = os.getenv("VIRTUAL_ENV")
|
||||
if (
|
||||
"PIPENV_ACTIVE" not in os.environ
|
||||
and not self.s.PIPENV_IGNORE_VIRTUALENVS and virtualenv_env
|
||||
and not self.s.PIPENV_IGNORE_VIRTUALENVS
|
||||
and virtualenv_env
|
||||
):
|
||||
return virtualenv_env
|
||||
|
||||
@@ -491,7 +503,7 @@ class Project:
|
||||
# type: (str) -> None
|
||||
"""Registers a proper name to the database."""
|
||||
with self.proper_names_db_path.open("a") as f:
|
||||
f.write(u"{0}\n".format(name))
|
||||
f.write("{0}\n".format(name))
|
||||
|
||||
@property
|
||||
def pipfile_location(self):
|
||||
@@ -632,8 +644,8 @@ class Project:
|
||||
|
||||
@property
|
||||
def _pipfile(self):
|
||||
from .vendor.requirementslib.models.pipfile import \
|
||||
Pipfile as ReqLibPipfile
|
||||
from .vendor.requirementslib.models.pipfile import Pipfile as ReqLibPipfile
|
||||
|
||||
pf = ReqLibPipfile.load(self.pipfile_location)
|
||||
return pf
|
||||
|
||||
@@ -660,6 +672,7 @@ class Project:
|
||||
|
||||
def _get_vcs_packages(self, dev=False):
|
||||
from pipenv.vendor.requirementslib.utils import is_vcs
|
||||
|
||||
section = "dev-packages" if dev else "packages"
|
||||
packages = {
|
||||
k: v
|
||||
@@ -727,15 +740,13 @@ class Project:
|
||||
|
||||
source_name = "pip_index_{}".format(i)
|
||||
verify_ssl = index.startswith("https")
|
||||
sources.append(
|
||||
{u"url": index, u"verify_ssl": verify_ssl, u"name": source_name}
|
||||
)
|
||||
sources.append({"url": index, "verify_ssl": verify_ssl, "name": source_name})
|
||||
|
||||
data = {
|
||||
u"source": sources,
|
||||
"source": sources,
|
||||
# Default packages.
|
||||
u"packages": {},
|
||||
u"dev-packages": {},
|
||||
"packages": {},
|
||||
"dev-packages": {},
|
||||
}
|
||||
# Default requires.
|
||||
required_python = python
|
||||
@@ -746,7 +757,7 @@ class Project:
|
||||
required_python = self.which("python")
|
||||
version = python_version(required_python) or self.s.PIPENV_DEFAULT_PYTHON_VERSION
|
||||
if version and len(version.split(".")) > 2:
|
||||
data[u"requires"] = {"python_version": ".".join(version.split(".")[:2])}
|
||||
data["requires"] = {"python_version": ".".join(version.split(".")[:2])}
|
||||
self.write_toml(data)
|
||||
|
||||
@classmethod
|
||||
@@ -762,13 +773,15 @@ class Project:
|
||||
return source
|
||||
|
||||
def get_or_create_lockfile(self, from_pipfile=False):
|
||||
from pipenv.vendor.requirementslib.models.lockfile import \
|
||||
Lockfile as Req_Lockfile
|
||||
from pipenv.vendor.requirementslib.models.lockfile import (
|
||||
Lockfile as Req_Lockfile,
|
||||
)
|
||||
|
||||
lockfile = None
|
||||
if from_pipfile and self.pipfile_exists:
|
||||
lockfile_dict = {
|
||||
"default": self._lockfile["default"].copy(),
|
||||
"develop": self._lockfile["develop"].copy()
|
||||
"develop": self._lockfile["develop"].copy(),
|
||||
}
|
||||
lockfile_dict.update({"_meta": self.get_lockfile_meta()})
|
||||
lockfile = Req_Lockfile.from_data(
|
||||
@@ -778,9 +791,13 @@ class Project:
|
||||
try:
|
||||
lockfile = Req_Lockfile.load(self.lockfile_location)
|
||||
except OSError:
|
||||
lockfile = Req_Lockfile.from_data(self.lockfile_location, self.lockfile_content)
|
||||
lockfile = Req_Lockfile.from_data(
|
||||
self.lockfile_location, self.lockfile_content
|
||||
)
|
||||
else:
|
||||
lockfile = Req_Lockfile.from_data(path=self.lockfile_location, data=self._lockfile, meta_from_project=False)
|
||||
lockfile = Req_Lockfile.from_data(
|
||||
path=self.lockfile_location, data=self._lockfile, meta_from_project=False
|
||||
)
|
||||
if lockfile._lockfile is not None:
|
||||
return lockfile
|
||||
if self.lockfile_exists and self.lockfile_content:
|
||||
@@ -790,9 +807,7 @@ class Project:
|
||||
sources = self.pipfile_sources
|
||||
elif not isinstance(sources, list):
|
||||
sources = [sources]
|
||||
lockfile_dict["_meta"]["sources"] = [
|
||||
self.populate_source(s) for s in sources
|
||||
]
|
||||
lockfile_dict["_meta"]["sources"] = [self.populate_source(s) for s in sources]
|
||||
_created_lockfile = Req_Lockfile.from_data(
|
||||
path=self.lockfile_location, data=lockfile_dict, meta_from_project=False
|
||||
)
|
||||
@@ -803,6 +818,7 @@ class Project:
|
||||
|
||||
def get_lockfile_meta(self):
|
||||
from .vendor.plette.lockfiles import PIPFILE_SPEC_CURRENT
|
||||
|
||||
if self.lockfile_exists:
|
||||
sources = self.lockfile_content.get("_meta", {}).get("sources", [])
|
||||
elif "source" in self.parsed_pipfile:
|
||||
@@ -815,7 +831,7 @@ class Project:
|
||||
"hash": {"sha256": self.calculate_pipfile_hash()},
|
||||
"pipfile-spec": PIPFILE_SPEC_CURRENT,
|
||||
"sources": [self.populate_source(s) for s in sources],
|
||||
"requires": self.parsed_pipfile.get("requires", {})
|
||||
"requires": self.parsed_pipfile.get("requires", {}),
|
||||
}
|
||||
|
||||
def write_toml(self, data, path=None):
|
||||
@@ -836,13 +852,12 @@ class Project:
|
||||
table.update(data[section][package])
|
||||
document[section][package] = table
|
||||
else:
|
||||
document[section][package] = tomlkit.string(data[section][package])
|
||||
document[section][package] = tomlkit.string(
|
||||
data[section][package]
|
||||
)
|
||||
formatted_data = tomlkit.dumps(document).rstrip()
|
||||
|
||||
if (
|
||||
Path(path).absolute()
|
||||
== Path(self.pipfile_location).absolute()
|
||||
):
|
||||
if Path(path).absolute() == Path(self.pipfile_location).absolute():
|
||||
newlines = self._pipfile_newlines
|
||||
else:
|
||||
newlines = DEFAULT_NEWLINES
|
||||
@@ -853,8 +868,7 @@ class Project:
|
||||
self.clear_pipfile_cache()
|
||||
|
||||
def write_lockfile(self, content):
|
||||
"""Write out the lockfile.
|
||||
"""
|
||||
"""Write out the lockfile."""
|
||||
s = self._lockfile_encoder.encode(content)
|
||||
open_kwargs = {"newline": self._lockfile_newlines, "encoding": "utf-8"}
|
||||
with vistir.contextmanagers.atomic_open_for_write(
|
||||
@@ -863,8 +877,8 @@ class Project:
|
||||
f.write(s)
|
||||
# Write newline at end of document. GH-319.
|
||||
# Only need '\n' here; the file object handles the rest.
|
||||
if not s.endswith(u"\n"):
|
||||
f.write(u"\n")
|
||||
if not s.endswith("\n"):
|
||||
f.write("\n")
|
||||
|
||||
@property
|
||||
def pipfile_sources(self):
|
||||
@@ -914,14 +928,18 @@ class Project:
|
||||
def find_source(sources, name=None, url=None):
|
||||
source = None
|
||||
if name:
|
||||
source = next(iter(
|
||||
s for s in sources if "name" in s and s["name"] == name
|
||||
), None)
|
||||
source = next(
|
||||
iter(s for s in sources if "name" in s and s["name"] == name), None
|
||||
)
|
||||
elif url:
|
||||
source = next(iter(
|
||||
s for s in sources
|
||||
source = next(
|
||||
iter(
|
||||
s
|
||||
for s in sources
|
||||
if "url" in s and is_url_equal(url, s.get("url", ""))
|
||||
), None)
|
||||
),
|
||||
None,
|
||||
)
|
||||
if source is not None:
|
||||
return source
|
||||
|
||||
@@ -961,9 +979,9 @@ class Project:
|
||||
packages = set([pep423_name(pkg) for pkg in packages])
|
||||
for section in ("dev-packages", "packages"):
|
||||
pipfile_section = parsed.get(section, {})
|
||||
pipfile_packages = set([
|
||||
pep423_name(pkg_name) for pkg_name in pipfile_section.keys()
|
||||
])
|
||||
pipfile_packages = set(
|
||||
[pep423_name(pkg_name) for pkg_name in pipfile_section.keys()]
|
||||
)
|
||||
to_remove = packages & pipfile_packages
|
||||
# The normal toml parser can't handle deleting packages with preceding newlines
|
||||
is_dev = section == "dev-packages"
|
||||
@@ -995,9 +1013,7 @@ class Project:
|
||||
self.write_toml(p)
|
||||
|
||||
def src_name_from_url(self, index_url):
|
||||
name, _, tld_guess = urllib.parse.urlsplit(index_url).netloc.rpartition(
|
||||
"."
|
||||
)
|
||||
name, _, tld_guess = urllib.parse.urlsplit(index_url).netloc.rpartition(".")
|
||||
src_name = name.replace(".", "")
|
||||
try:
|
||||
self.get_source(name=src_name)
|
||||
@@ -1005,6 +1021,7 @@ class Project:
|
||||
name = src_name
|
||||
else:
|
||||
from random import randint
|
||||
|
||||
name = "{0}-{1}".format(src_name, randint(1, 1000))
|
||||
return name
|
||||
|
||||
@@ -1109,6 +1126,7 @@ class Project:
|
||||
@cached_property
|
||||
def finders(self):
|
||||
from .vendor.pythonfinder import Finder
|
||||
|
||||
scripts_dirname = "Scripts" if os.name == "nt" else "bin"
|
||||
scripts_dir = os.path.join(self.virtualenv_location, scripts_dirname)
|
||||
finders = [
|
||||
|
||||
+157
-67
@@ -3,12 +3,12 @@ import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
os.environ["PIP_PYTHON_PATH"] = str(sys.executable)
|
||||
|
||||
|
||||
def find_site_path(pkg, site_dir=None):
|
||||
import pkg_resources
|
||||
|
||||
if site_dir is None:
|
||||
site_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
working_set = pkg_resources.WorkingSet([site_dir] + sys.path[:])
|
||||
@@ -17,7 +17,16 @@ def find_site_path(pkg, site_dir=None):
|
||||
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([line.strip() for line in dist.get_metadata_lines("top_level.txt") if line is not None]), None)
|
||||
name = next(
|
||||
iter(
|
||||
[
|
||||
line.strip()
|
||||
for line in dist.get_metadata_lines("top_level.txt")
|
||||
if line 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]):
|
||||
@@ -26,15 +35,15 @@ def find_site_path(pkg, site_dir=None):
|
||||
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)
|
||||
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)
|
||||
pipenv_dist = None
|
||||
if pipenv_site is not None:
|
||||
pipenv_dist, pipenv_path = find_site_path("pipenv", site_dir=pipenv_site)
|
||||
else:
|
||||
@@ -42,10 +51,16 @@ def _patch_path(pipenv_site=None):
|
||||
if pipenv_dist is not None:
|
||||
pipenv_dist.activate()
|
||||
else:
|
||||
site.addsitedir(next(iter(
|
||||
sitedir for sitedir in (pipenv_site, pipenv_site_dir)
|
||||
site.addsitedir(
|
||||
next(
|
||||
iter(
|
||||
sitedir
|
||||
for sitedir in (pipenv_site, pipenv_site_dir)
|
||||
if sitedir is not None
|
||||
), None))
|
||||
),
|
||||
None,
|
||||
)
|
||||
)
|
||||
if pipenv_path is not None:
|
||||
pipenv_libdir = pipenv_path
|
||||
for _dir in ("vendor", "patched", pipenv_libdir):
|
||||
@@ -54,6 +69,7 @@ def _patch_path(pipenv_site=None):
|
||||
|
||||
def get_parser():
|
||||
from argparse import ArgumentParser
|
||||
|
||||
parser = ArgumentParser("pipenv-resolver")
|
||||
parser.add_argument("--pre", action="store_true", default=False)
|
||||
parser.add_argument("--clear", action="store_true", default=False)
|
||||
@@ -62,12 +78,24 @@ def get_parser():
|
||||
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"))
|
||||
parser.add_argument("--write", metavar="write", action="store",
|
||||
default=os.environ.get("PIPENV_RESOLVER_FILE"))
|
||||
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"),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--write",
|
||||
metavar="write",
|
||||
action="store",
|
||||
default=os.environ.get("PIPENV_RESOLVER_FILE"),
|
||||
)
|
||||
parser.add_argument("packages", nargs="*")
|
||||
return parser
|
||||
|
||||
@@ -103,6 +131,7 @@ class Entry:
|
||||
def __init__(self, name, entry_dict, project, resolver, reverse_deps=None, dev=False):
|
||||
super().__init__()
|
||||
from pipenv.vendor.requirementslib.models.utils import tomlkit_value_to_python
|
||||
|
||||
self.name = name
|
||||
if isinstance(entry_dict, dict):
|
||||
self.entry_dict = self.clean_initial_dict(entry_dict)
|
||||
@@ -137,6 +166,7 @@ class Entry:
|
||||
@staticmethod
|
||||
def make_requirement(name=None, entry=None, from_ireq=False):
|
||||
from pipenv.vendor.requirementslib.models.requirements import Requirement
|
||||
|
||||
if from_ireq:
|
||||
return Requirement.from_ireq(entry)
|
||||
return Requirement.from_pipfile(name, entry)
|
||||
@@ -152,12 +182,11 @@ class Entry:
|
||||
@classmethod
|
||||
def parse_pyparsing_exprs(cls, expr_iterable):
|
||||
from pipenv.vendor.pyparsing import Literal, MatchFirst
|
||||
|
||||
keys = []
|
||||
expr_list = []
|
||||
expr = expr_iterable.copy()
|
||||
if isinstance(expr, Literal) or (
|
||||
expr.__class__.__name__ == Literal.__name__
|
||||
):
|
||||
if isinstance(expr, Literal) or (expr.__class__.__name__ == Literal.__name__):
|
||||
keys.append(expr.match)
|
||||
elif isinstance(expr, MatchFirst) or (
|
||||
expr.__class__.__name__ == MatchFirst.__name__
|
||||
@@ -174,13 +203,11 @@ class Entry:
|
||||
def get_markers_from_dict(cls, entry_dict):
|
||||
from pipenv.vendor.packaging import markers as packaging_markers
|
||||
from pipenv.vendor.requirementslib.models.markers import normalize_marker_str
|
||||
|
||||
marker_keys = cls.parse_pyparsing_exprs(packaging_markers.VARIABLE)
|
||||
markers = set()
|
||||
keys_in_dict = [k for k in marker_keys if k in entry_dict]
|
||||
markers = {
|
||||
normalize_marker_str(f"{k} {entry_dict.pop(k)}")
|
||||
for k in keys_in_dict
|
||||
}
|
||||
markers = {normalize_marker_str(f"{k} {entry_dict.pop(k)}") for k in keys_in_dict}
|
||||
if "markers" in entry_dict:
|
||||
markers.add(normalize_marker_str(entry_dict["markers"]))
|
||||
if None in markers:
|
||||
@@ -209,9 +236,7 @@ class Entry:
|
||||
|
||||
@property
|
||||
def original_markers(self):
|
||||
original_markers, lockfile_dict = self.get_markers_from_dict(
|
||||
self.lockfile_dict
|
||||
)
|
||||
original_markers, lockfile_dict = self.get_markers_from_dict(self.lockfile_dict)
|
||||
self.lockfile_dict = lockfile_dict
|
||||
self._original_markers = self.marker_to_str(original_markers)
|
||||
return self._original_markers
|
||||
@@ -219,9 +244,11 @@ class Entry:
|
||||
@staticmethod
|
||||
def marker_to_str(marker):
|
||||
from pipenv.vendor.requirementslib.models.markers import normalize_marker_str
|
||||
|
||||
if not marker:
|
||||
return None
|
||||
from pipenv.vendor.vistir.compat import Mapping
|
||||
|
||||
marker_str = None
|
||||
if isinstance(marker, Mapping):
|
||||
marker_dict, _ = Entry.get_markers_from_dict(marker)
|
||||
@@ -274,7 +301,9 @@ class Entry:
|
||||
@property
|
||||
def pipfile_entry(self):
|
||||
if self._pipfile_entry is None:
|
||||
self._pipfile_entry = self.make_requirement(self.pipfile_name, self.pipfile_dict)
|
||||
self._pipfile_entry = self.make_requirement(
|
||||
self.pipfile_name, self.pipfile_dict
|
||||
)
|
||||
return self._pipfile_entry
|
||||
|
||||
@property
|
||||
@@ -300,8 +329,9 @@ class Entry:
|
||||
return self.project.pipfile_package_names["dev" if self.dev else "default"]
|
||||
|
||||
def create_parent(self, name, specifier="*"):
|
||||
parent = self.create(name, specifier, self.project, self.resolver,
|
||||
self.reverse_deps, self.dev)
|
||||
parent = self.create(
|
||||
name, specifier, self.project, self.resolver, self.reverse_deps, self.dev
|
||||
)
|
||||
parent._deptree = self.deptree
|
||||
return parent
|
||||
|
||||
@@ -318,6 +348,7 @@ class Entry:
|
||||
@staticmethod
|
||||
def clean_specifier(specifier):
|
||||
from pipenv.vendor.packaging.specifiers import Specifier
|
||||
|
||||
if not any(specifier.startswith(k) for k in Specifier._operators.keys()):
|
||||
if specifier.strip().lower() in ["any", "<any>", "*"]:
|
||||
return "*"
|
||||
@@ -329,15 +360,17 @@ class Entry:
|
||||
@staticmethod
|
||||
def strip_version(specifier):
|
||||
from pipenv.vendor.packaging.specifiers import Specifier
|
||||
op = next(iter(
|
||||
k for k in Specifier._operators.keys() if specifier.startswith(k)
|
||||
), None)
|
||||
|
||||
op = next(
|
||||
iter(k for k in Specifier._operators.keys() if specifier.startswith(k)), None
|
||||
)
|
||||
if op:
|
||||
specifier = specifier[len(op) :]
|
||||
while op:
|
||||
op = next(iter(
|
||||
k for k in Specifier._operators.keys() if specifier.startswith(k)
|
||||
), None)
|
||||
op = next(
|
||||
iter(k for k in Specifier._operators.keys() if specifier.startswith(k)),
|
||||
None,
|
||||
)
|
||||
if op:
|
||||
specifier = specifier[len(op) :]
|
||||
return specifier
|
||||
@@ -358,7 +391,8 @@ class Entry:
|
||||
def parents_in_pipfile(self):
|
||||
if not self._parents_in_pipfile:
|
||||
self._parents_in_pipfile = [
|
||||
p for p in self.flattened_parents
|
||||
p
|
||||
for p in self.flattened_parents
|
||||
if p.normalized_name in self.pipfile_packages
|
||||
]
|
||||
return self._parents_in_pipfile
|
||||
@@ -370,9 +404,9 @@ class Entry:
|
||||
@property
|
||||
def requirements(self):
|
||||
if not self._requires:
|
||||
self._requires = next(iter(
|
||||
self.project.environment.get_package_requirements(self.name)
|
||||
), {})
|
||||
self._requires = next(
|
||||
iter(self.project.environment.get_package_requirements(self.name)), {}
|
||||
)
|
||||
return self._requires
|
||||
|
||||
@property
|
||||
@@ -403,14 +437,19 @@ class Entry:
|
||||
|
||||
def get_dependency(self, name):
|
||||
if self.requirements:
|
||||
return next(iter(
|
||||
dep for dep in self.requirements.get("dependencies", [])
|
||||
return next(
|
||||
iter(
|
||||
dep
|
||||
for dep in self.requirements.get("dependencies", [])
|
||||
if dep and dep.get("package_name", "") == name
|
||||
), {})
|
||||
),
|
||||
{},
|
||||
)
|
||||
return {}
|
||||
|
||||
def get_parent_deps(self, unnest=False):
|
||||
from pipenv.vendor.packaging.specifiers import Specifier
|
||||
|
||||
parents = []
|
||||
for spec in self.reverse_deps.get(self.normalized_name, {}).get("parents", set()):
|
||||
spec_match = next(iter(c for c in Specifier._operators if c in spec), None)
|
||||
@@ -418,7 +457,9 @@ class Entry:
|
||||
parent = None
|
||||
if spec_match is not None:
|
||||
spec_index = spec.index(spec_match)
|
||||
specifier = self.clean_specifier(spec[spec_index:len(spec_match)]).strip()
|
||||
specifier = self.clean_specifier(
|
||||
spec[spec_index : len(spec_match)]
|
||||
).strip()
|
||||
name_start = spec_index + len(spec_match)
|
||||
name = spec[name_start:].strip()
|
||||
parent = self.create_parent(name, specifier)
|
||||
@@ -460,13 +501,16 @@ class Entry:
|
||||
self.entry_dict = self.lockfile_dict.copy()
|
||||
elif can_use_updated:
|
||||
if len(satisfied_by_versions) == 1:
|
||||
self.entry_dict["version"] = next(iter(
|
||||
sat_by for sat_by in satisfied_by_versions if sat_by
|
||||
), None)
|
||||
self.entry_dict["version"] = next(
|
||||
iter(sat_by for sat_by in satisfied_by_versions if sat_by), None
|
||||
)
|
||||
hashes = None
|
||||
if self.lockfile_entry.specifiers == satisfied_by:
|
||||
ireq = self.lockfile_entry.as_ireq()
|
||||
if not self.lockfile_entry.hashes and self.resolver._should_include_hash(ireq):
|
||||
if (
|
||||
not self.lockfile_entry.hashes
|
||||
and self.resolver._should_include_hash(ireq)
|
||||
):
|
||||
hashes = self.resolver.get_hash(ireq)
|
||||
else:
|
||||
hashes = self.lockfile_entry.hashes
|
||||
@@ -491,11 +535,12 @@ class Entry:
|
||||
:rtype: Set
|
||||
"""
|
||||
constraints = {
|
||||
c for c in self.resolver.parsed_constraints
|
||||
if c and c.name == self.entry.name
|
||||
c for c in self.resolver.parsed_constraints if c and c.name == self.entry.name
|
||||
}
|
||||
pipfile_constraint = self.get_pipfile_constraint()
|
||||
if pipfile_constraint and not (self.pipfile_entry.editable or pipfile_constraint.editable):
|
||||
if pipfile_constraint and not (
|
||||
self.pipfile_entry.editable or pipfile_constraint.editable
|
||||
):
|
||||
constraints.add(pipfile_constraint)
|
||||
return constraints
|
||||
|
||||
@@ -532,8 +577,10 @@ class Entry:
|
||||
msg = (
|
||||
"Cannot resolve conflicting version {}{} while {}{} is "
|
||||
"locked.".format(
|
||||
self.name, constraint.req.specifier,
|
||||
self.name, self.updated_specifier
|
||||
self.name,
|
||||
constraint.req.specifier,
|
||||
self.name,
|
||||
self.updated_specifier,
|
||||
)
|
||||
)
|
||||
raise DependencyConflict(msg)
|
||||
@@ -545,12 +592,15 @@ class Entry:
|
||||
continue
|
||||
if not parent.validate_specifiers():
|
||||
from pipenv.exceptions import DependencyConflict
|
||||
|
||||
msg = (
|
||||
"Cannot resolve conflicting versions: (Root: {}) {}{} (Pipfile) "
|
||||
"Incompatible with {}{} (resolved)\n".format(
|
||||
self.name, parent.pipfile_name,
|
||||
parent.pipfile_entry.requirement.specifiers, parent.name,
|
||||
parent.updated_specifiers
|
||||
self.name,
|
||||
parent.pipfile_name,
|
||||
parent.pipfile_entry.requirement.specifiers,
|
||||
parent.name,
|
||||
parent.updated_specifiers,
|
||||
)
|
||||
)
|
||||
raise DependencyConflict(msg)
|
||||
@@ -586,6 +636,7 @@ class Entry:
|
||||
|
||||
def clean_results(results, resolver, project, dev=False):
|
||||
from pipenv.utils.dependencies import translate_markers
|
||||
|
||||
if not project.lockfile_exists:
|
||||
return results
|
||||
lockfile = project.lockfile_content
|
||||
@@ -595,7 +646,9 @@ def clean_results(results, resolver, project, dev=False):
|
||||
for result in results:
|
||||
name = result.get("name")
|
||||
entry_dict = result.copy()
|
||||
entry = Entry(name, entry_dict, project, resolver, reverse_deps=reverse_deps, dev=dev)
|
||||
entry = Entry(
|
||||
name, entry_dict, project, resolver, reverse_deps=reverse_deps, dev=dev
|
||||
)
|
||||
entry_dict = translate_markers(entry.get_cleaned_dict(keep_outdated=False))
|
||||
new_results.append(entry_dict)
|
||||
return new_results
|
||||
@@ -611,7 +664,9 @@ def clean_outdated(results, resolver, project, dev=False):
|
||||
for result in results:
|
||||
name = result.get("name")
|
||||
entry_dict = result.copy()
|
||||
entry = Entry(name, entry_dict, project, resolver, reverse_deps=reverse_deps, dev=dev)
|
||||
entry = Entry(
|
||||
name, entry_dict, project, resolver, reverse_deps=reverse_deps, dev=dev
|
||||
)
|
||||
# The old entry was editable but this one isnt; prefer the old one
|
||||
# TODO: Should this be the case for all locking?
|
||||
if entry.was_editable and not entry.is_editable:
|
||||
@@ -622,9 +677,17 @@ def clean_outdated(results, resolver, project, dev=False):
|
||||
if name in lockfile[alternate_section]:
|
||||
lockfile_entry = lockfile[alternate_section][name]
|
||||
if lockfile_entry and not entry.is_updated:
|
||||
old_markers = next(iter(m for m in (
|
||||
entry.lockfile_entry.markers, lockfile_entry.get("markers", None)
|
||||
) if m is not None), None)
|
||||
old_markers = next(
|
||||
iter(
|
||||
m
|
||||
for m in (
|
||||
entry.lockfile_entry.markers,
|
||||
lockfile_entry.get("markers", None),
|
||||
)
|
||||
if m is not None
|
||||
),
|
||||
None,
|
||||
)
|
||||
new_markers = entry_dict.get("markers", None)
|
||||
if old_markers:
|
||||
old_markers = Entry.marker_to_str(old_markers)
|
||||
@@ -644,14 +707,15 @@ def clean_outdated(results, resolver, project, dev=False):
|
||||
|
||||
|
||||
def parse_packages(packages, pre, clear, system, requirements_dir=None):
|
||||
from pipenv.utils.indexes import parse_indexes
|
||||
from pipenv.vendor.requirementslib.models.requirements import Requirement
|
||||
from pipenv.vendor.vistir.contextmanagers import cd, temp_path
|
||||
from pipenv.utils.indexes import parse_indexes
|
||||
|
||||
parsed_packages = []
|
||||
for package in packages:
|
||||
*_, line = parse_indexes(package)
|
||||
line = " ".join(line)
|
||||
pf = dict()
|
||||
pf = {}
|
||||
req = Requirement.from_line(line)
|
||||
if not req.name:
|
||||
with temp_path(), cd(req.req.setup_info.base_dir):
|
||||
@@ -676,6 +740,7 @@ def parse_packages(packages, pre, clear, system, requirements_dir=None):
|
||||
def resolve_packages(pre, clear, verbose, system, write, requirements_dir, packages, dev):
|
||||
from pipenv.utils.internet import create_mirror_source, replace_pypi_sources
|
||||
from pipenv.utils.resolver import resolve_deps
|
||||
|
||||
pypi_mirror_source = (
|
||||
create_mirror_source(os.environ["PIPENV_PYPI_MIRROR"])
|
||||
if "PIPENV_PYPI_MIRROR" in os.environ
|
||||
@@ -691,10 +756,11 @@ def resolve_packages(pre, clear, verbose, system, write, requirements_dir, packa
|
||||
sources=sources,
|
||||
clear=clear,
|
||||
allow_global=system,
|
||||
req_dir=requirements_dir
|
||||
req_dir=requirements_dir,
|
||||
)
|
||||
|
||||
from pipenv.project import Project
|
||||
|
||||
project = Project()
|
||||
sources = (
|
||||
replace_pypi_sources(project.pipfile_sources, pypi_mirror_source)
|
||||
@@ -729,8 +795,20 @@ def resolve_packages(pre, clear, verbose, system, write, requirements_dir, packa
|
||||
print(json.dumps([]))
|
||||
|
||||
|
||||
def _main(pre, clear, verbose, system, write, requirements_dir, packages, parse_only=False, dev=False):
|
||||
os.environ["PIPENV_REQUESTED_PYTHON_VERSION"] = ".".join([str(s) for s in sys.version_info[:3]])
|
||||
def _main(
|
||||
pre,
|
||||
clear,
|
||||
verbose,
|
||||
system,
|
||||
write,
|
||||
requirements_dir,
|
||||
packages,
|
||||
parse_only=False,
|
||||
dev=False,
|
||||
):
|
||||
os.environ["PIPENV_REQUESTED_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(
|
||||
@@ -741,7 +819,9 @@ def _main(pre, clear, verbose, system, write, requirements_dir, packages, parse_
|
||||
requirements_dir=requirements_dir,
|
||||
)
|
||||
else:
|
||||
resolve_packages(pre, clear, verbose, system, write, requirements_dir, packages, dev)
|
||||
resolve_packages(
|
||||
pre, clear, verbose, system, write, requirements_dir, packages, dev
|
||||
)
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
@@ -749,8 +829,10 @@ def main(argv=None):
|
||||
parsed, remaining = parser.parse_known_args(argv)
|
||||
_patch_path(pipenv_site=parsed.pipenv_site)
|
||||
import warnings
|
||||
|
||||
from pipenv.vendor.vistir.compat import ResourceWarning
|
||||
from pipenv.vendor.vistir.misc import replace_with_text_stream
|
||||
|
||||
warnings.simplefilter("ignore", category=ResourceWarning)
|
||||
replace_with_text_stream("stdout")
|
||||
replace_with_text_stream("stderr")
|
||||
@@ -758,9 +840,17 @@ def main(argv=None):
|
||||
os.environ["PYTHONIOENCODING"] = "utf-8"
|
||||
os.environ["PYTHONUNBUFFERED"] = "1"
|
||||
parsed = handle_parsed_args(parsed)
|
||||
_main(parsed.pre, parsed.clear, parsed.verbose, parsed.system, parsed.write,
|
||||
parsed.requirements_dir, parsed.packages, parse_only=parsed.parse_only,
|
||||
dev=parsed.dev)
|
||||
_main(
|
||||
parsed.pre,
|
||||
parsed.clear,
|
||||
parsed.verbose,
|
||||
parsed.system,
|
||||
parsed.write,
|
||||
parsed.requirements_dir,
|
||||
parsed.packages,
|
||||
parse_only=parsed.parse_only,
|
||||
dev=parsed.dev,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+14
-12
@@ -10,7 +10,6 @@ from pipenv.vendor import shellingham
|
||||
from pipenv.vendor.vistir.compat import Path, get_terminal_size
|
||||
from pipenv.vendor.vistir.contextmanagers import temp_environ
|
||||
|
||||
|
||||
ShellDetectionFailure = shellingham.ShellDetectionFailure
|
||||
|
||||
|
||||
@@ -49,7 +48,7 @@ def _get_activate_script(cmd, venv):
|
||||
command = "."
|
||||
# Escape any special characters located within the virtualenv path to allow
|
||||
# for proper activation.
|
||||
venv_location = re.sub(r'([ &$()\[\]])', r"\\\1", str(venv))
|
||||
venv_location = re.sub(r"([ &$()\[\]])", r"\\\1", str(venv))
|
||||
# The leading space can make history cleaner in some shells.
|
||||
return f" {command} {venv_location}/bin/activate{suffix}"
|
||||
|
||||
@@ -68,7 +67,7 @@ class Shell:
|
||||
self.args = []
|
||||
|
||||
def __repr__(self):
|
||||
return '{type}(cmd={cmd!r})'.format(
|
||||
return "{type}(cmd={cmd!r})".format(
|
||||
type=type(self).__name__,
|
||||
cmd=self.cmd,
|
||||
)
|
||||
@@ -149,10 +148,9 @@ class Bash(Shell):
|
||||
base_rc_src = f'source "{bashrc_path.as_posix()}"\n'
|
||||
rcfile.write(base_rc_src)
|
||||
|
||||
export_path = 'export PATH="{}:$PATH"\n'.format(":".join(
|
||||
self._format_path(python)
|
||||
for python in _iter_python(venv)
|
||||
))
|
||||
export_path = 'export PATH="{}:$PATH"\n'.format(
|
||||
":".join(self._format_path(python) for python in _iter_python(venv))
|
||||
)
|
||||
rcfile.write(export_path)
|
||||
rcfile.flush()
|
||||
self.args.extend(["--rcfile", rcfile.name])
|
||||
@@ -165,7 +163,7 @@ class MsysBash(Bash):
|
||||
if not python.drive:
|
||||
return s
|
||||
# Convert "C:/something" to "/c/something".
|
||||
return f'/{s[0].lower()}{s[2:]}'
|
||||
return f"/{s[0].lower()}{s[2:]}"
|
||||
|
||||
|
||||
class CmderEmulatedShell(Shell):
|
||||
@@ -207,16 +205,20 @@ SHELL_LOOKUP = collections.defaultdict(
|
||||
lambda: collections.defaultdict(lambda: Shell),
|
||||
{
|
||||
"bash": collections.defaultdict(
|
||||
lambda: Bash, {"msys": MsysBash},
|
||||
lambda: Bash,
|
||||
{"msys": MsysBash},
|
||||
),
|
||||
"cmd": collections.defaultdict(
|
||||
lambda: Shell, {"cmder": CmderCommandPrompt},
|
||||
lambda: Shell,
|
||||
{"cmder": CmderCommandPrompt},
|
||||
),
|
||||
"powershell": collections.defaultdict(
|
||||
lambda: Shell, {"cmder": CmderPowershell},
|
||||
lambda: Shell,
|
||||
{"cmder": CmderPowershell},
|
||||
),
|
||||
"pwsh": collections.defaultdict(
|
||||
lambda: Shell, {"cmder": CmderPowershell},
|
||||
lambda: Shell,
|
||||
{"cmder": CmderPowershell},
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
import logging
|
||||
|
||||
logging.basicConfig(level=logging.ERROR)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import os
|
||||
import re
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
|
||||
from typing import Sequence, Mapping
|
||||
from typing import Mapping, Sequence
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from packaging.markers import Marker
|
||||
|
||||
from pipenv import fs_str
|
||||
|
||||
from .constants import SCHEME_LIST, VCS_LIST
|
||||
from .shell import temp_path
|
||||
|
||||
@@ -80,13 +80,7 @@ def pep423_name(name):
|
||||
return name
|
||||
|
||||
|
||||
def get_vcs_deps(
|
||||
project=None,
|
||||
dev=False,
|
||||
pypi_mirror=None,
|
||||
packages=None,
|
||||
reqs=None
|
||||
):
|
||||
def get_vcs_deps(project=None, dev=False, pypi_mirror=None, packages=None, reqs=None):
|
||||
from pipenv.vendor.requirementslib.models.requirements import Requirement
|
||||
|
||||
section = "vcs_dev_packages" if dev else "vcs_packages"
|
||||
@@ -112,7 +106,7 @@ def get_vcs_deps(
|
||||
try:
|
||||
with temp_path(), locked_repository(requirement) as repo:
|
||||
from pipenv.vendor.requirementslib.models.requirements import (
|
||||
Requirement
|
||||
Requirement,
|
||||
)
|
||||
|
||||
# from distutils.sysconfig import get_python_lib
|
||||
@@ -120,7 +114,7 @@ def get_vcs_deps(
|
||||
commit_hash = repo.get_commit_hash()
|
||||
name = requirement.normalized_name
|
||||
lockfile[name] = requirement.pipfile_entry[1]
|
||||
lockfile[name]['ref'] = commit_hash
|
||||
lockfile[name]["ref"] = commit_hash
|
||||
result.append(requirement)
|
||||
except OSError:
|
||||
continue
|
||||
@@ -152,7 +146,7 @@ def translate_markers(pipfile_entry):
|
||||
marker_str = new_pipfile.pop("markers")
|
||||
if marker_str:
|
||||
marker = str(Marker(marker_str))
|
||||
if 'extra' not in marker:
|
||||
if "extra" not in marker:
|
||||
marker_set.add(marker)
|
||||
for m in pipfile_markers:
|
||||
entry = f"{pipfile_entry[m]}"
|
||||
@@ -160,15 +154,19 @@ def translate_markers(pipfile_entry):
|
||||
marker_set.add(str(Marker(f"{m} {entry}")))
|
||||
new_pipfile.pop(m)
|
||||
if marker_set:
|
||||
new_pipfile["markers"] = str(Marker(" or ".join(
|
||||
f"{s}" if " and " in s else s
|
||||
for s in sorted(dedup(marker_set))
|
||||
))).replace('"', "'")
|
||||
new_pipfile["markers"] = str(
|
||||
Marker(
|
||||
" or ".join(
|
||||
f"{s}" if " and " in s else s for s in sorted(dedup(marker_set))
|
||||
)
|
||||
)
|
||||
).replace('"', "'")
|
||||
return new_pipfile
|
||||
|
||||
|
||||
def clean_resolved_dep(dep, is_top_level=False, pipfile_entry=None):
|
||||
from pipenv.vendor.requirementslib.utils import is_vcs
|
||||
|
||||
name = pep423_name(dep["name"])
|
||||
lockfile = {}
|
||||
# We use this to determine if there are any markers on top level packages
|
||||
@@ -195,7 +193,9 @@ def clean_resolved_dep(dep, is_top_level=False, pipfile_entry=None):
|
||||
fs_key = next(iter(k for k in ["path", "file"] if k in dep), None)
|
||||
pipfile_fs_key = None
|
||||
if pipfile_entry:
|
||||
pipfile_fs_key = next(iter(k for k in ["path", "file"] if k in pipfile_entry), None)
|
||||
pipfile_fs_key = next(
|
||||
iter(k for k in ["path", "file"] if k in pipfile_entry), None
|
||||
)
|
||||
if fs_key and pipfile_fs_key and fs_key != pipfile_fs_key:
|
||||
lockfile[pipfile_fs_key] = pipfile_entry[pipfile_fs_key]
|
||||
elif fs_key is not None:
|
||||
@@ -266,6 +266,7 @@ def convert_deps_to_pip(deps, project=None, r=True, include_index=True):
|
||||
|
||||
# Write requirements.txt to tmp directory.
|
||||
from pipenv.vendor.vistir.path import create_tracked_tempfile
|
||||
|
||||
f = create_tracked_tempfile(suffix="-requirements.txt", delete=False)
|
||||
f.write("\n".join(dependencies).encode("utf-8"))
|
||||
f.close()
|
||||
@@ -333,6 +334,7 @@ def is_installable_file(path):
|
||||
@contextmanager
|
||||
def locked_repository(requirement):
|
||||
from pipenv.vendor.vistir.path import create_tracked_tempdir
|
||||
|
||||
if not requirement.is_vcs:
|
||||
return
|
||||
original_base = os.environ.pop("PIP_SHIMS_BASE_MODULE", None)
|
||||
|
||||
+20
-22
@@ -1,18 +1,18 @@
|
||||
import re
|
||||
|
||||
from urllib3.util import parse_url
|
||||
|
||||
from pipenv import environments
|
||||
if environments.MYPY_RUNNING:
|
||||
from typing import List, Optional, Text, Tuple, Union
|
||||
|
||||
from pipenv.project import Project, TSource
|
||||
from pipenv.vendor.requirementslib.models.requirements import Requirement
|
||||
|
||||
from urllib3 import util as urllib3_util
|
||||
from requirementslib import Requirement
|
||||
|
||||
from pipenv.vendor.vistir.compat import Mapping
|
||||
from pipenv.exceptions import PipenvUsageError
|
||||
from pipenv.vendor.vistir.compat import Mapping
|
||||
|
||||
from .internet import create_mirror_source, is_pypi_url
|
||||
|
||||
if environments.MYPY_RUNNING:
|
||||
from typing import List, Optional, Union # noqa
|
||||
|
||||
from pipenv.project import Project, TSource # noqa
|
||||
|
||||
|
||||
def prepare_pip_source_args(sources, pip_args=None):
|
||||
if pip_args is None:
|
||||
@@ -25,11 +25,9 @@ def prepare_pip_source_args(sources, pip_args=None):
|
||||
pip_args.extend(["-i", package_url])
|
||||
# Trust the host if it's not verified.
|
||||
if not sources[0].get("verify_ssl", True):
|
||||
url_parts = urllib3_util.parse_url(package_url)
|
||||
url_parts = parse_url(package_url)
|
||||
url_port = f":{url_parts.port}" if url_parts.port else ""
|
||||
pip_args.extend(
|
||||
["--trusted-host", f"{url_parts.host}{url_port}"]
|
||||
)
|
||||
pip_args.extend(["--trusted-host", f"{url_parts.host}{url_port}"])
|
||||
# Add additional sources as extra indexes.
|
||||
if len(sources) > 1:
|
||||
for source in sources[1:]:
|
||||
@@ -39,17 +37,16 @@ def prepare_pip_source_args(sources, pip_args=None):
|
||||
pip_args.extend(["--extra-index-url", url])
|
||||
# Trust the host if it's not verified.
|
||||
if not source.get("verify_ssl", True):
|
||||
url_parts = urllib3_util.parse_url(url)
|
||||
url_parts = parse_url(url)
|
||||
url_port = f":{url_parts.port}" if url_parts.port else ""
|
||||
pip_args.extend(
|
||||
["--trusted-host", f"{url_parts.host}{url_port}"]
|
||||
)
|
||||
pip_args.extend(["--trusted-host", f"{url_parts.host}{url_port}"])
|
||||
return pip_args
|
||||
|
||||
|
||||
def get_project_index(project, index=None, trusted_hosts=None):
|
||||
# type: (Optional[Union[str, TSource]], Optional[List[str]], Optional[Project]) -> TSource
|
||||
from pipenv.project import SourceNotFound
|
||||
|
||||
if trusted_hosts is None:
|
||||
trusted_hosts = []
|
||||
if isinstance(index, Mapping):
|
||||
@@ -57,7 +54,7 @@ def get_project_index(project, index=None, trusted_hosts=None):
|
||||
try:
|
||||
source = project.find_source(index)
|
||||
except SourceNotFound:
|
||||
index_url = urllib3_util.parse_url(index)
|
||||
index_url = parse_url(index)
|
||||
src_name = project.src_name_from_url(index)
|
||||
verify_ssl = index_url.host not in trusted_hosts
|
||||
source = {"url": index, "verify_ssl": verify_ssl, "name": src_name}
|
||||
@@ -109,8 +106,9 @@ def parse_indexes(line, strict=False):
|
||||
index = args.index
|
||||
extra_index = args.extra_index
|
||||
trusted_host = args.trusted_host
|
||||
if strict and sum(
|
||||
bool(arg) for arg in (index, extra_index, trusted_host, remainder)
|
||||
) > 1:
|
||||
if (
|
||||
strict
|
||||
and sum(bool(arg) for arg in (index, extra_index, trusted_host, remainder)) > 1
|
||||
):
|
||||
raise ValueError("Index arguments must be on their own lines.")
|
||||
return index, extra_index, trusted_host, remainder
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import re
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from urllib3 import util as urllib3_util
|
||||
|
||||
from pipenv.vendor import parse
|
||||
@@ -75,7 +76,7 @@ def get_host_and_port(url):
|
||||
:return: a string with the host:port pair if the URL includes port number explicitly; otherwise, returns host only
|
||||
"""
|
||||
url = urllib3_util.parse_url(url)
|
||||
return '{}:{}'.format(url.host, url.port) if url.port else url.host
|
||||
return "{}:{}".format(url.host, url.port) if url.port else url.host
|
||||
|
||||
|
||||
def get_url_name(url):
|
||||
@@ -120,9 +121,7 @@ def proper_case(package_name):
|
||||
f"https://pypi.org/pypi/{package_name}/json", timeout=0.3, stream=True
|
||||
)
|
||||
if not r.ok:
|
||||
raise OSError(
|
||||
f"Unable to find package {package_name} in PyPI repository."
|
||||
)
|
||||
raise OSError(f"Unable to find package {package_name} in PyPI repository.")
|
||||
|
||||
r = parse.parse("https://pypi.org/pypi/{name}/json", r.url)
|
||||
good_name = r["name"]
|
||||
|
||||
+11
-10
@@ -1,6 +1,6 @@
|
||||
from typing import Mapping
|
||||
|
||||
from .dependencies import pep423_name, translate_markers, clean_resolved_dep
|
||||
from .dependencies import clean_resolved_dep, pep423_name, translate_markers
|
||||
|
||||
|
||||
def format_requirement_for_lockfile(req, markers_lookup, index_lookup, hashes=None):
|
||||
@@ -44,16 +44,12 @@ def get_locked_dep(dep, pipfile_section, prefer_pipfile=True):
|
||||
# it now for development purposes
|
||||
# TODO: Is this implementation clear? How can it be improved?
|
||||
entry = None
|
||||
cleaner_kwargs = {
|
||||
"is_top_level": False,
|
||||
"pipfile_entry": None
|
||||
}
|
||||
cleaner_kwargs = {"is_top_level": False, "pipfile_entry": None}
|
||||
if isinstance(dep, Mapping) and dep.get("name", ""):
|
||||
dep_name = pep423_name(dep["name"])
|
||||
name = next(iter(
|
||||
k for k in pipfile_section.keys()
|
||||
if pep423_name(k) == dep_name
|
||||
), None)
|
||||
name = next(
|
||||
iter(k for k in pipfile_section.keys() if pep423_name(k) == dep_name), None
|
||||
)
|
||||
entry = pipfile_section[name] if name else None
|
||||
|
||||
if entry:
|
||||
@@ -66,7 +62,12 @@ def get_locked_dep(dep, pipfile_section, prefer_pipfile=True):
|
||||
lockfile_name, lockfile_dict = lockfile_entry.copy().popitem()
|
||||
lockfile_version = lockfile_dict.get("version", "")
|
||||
# Keep pins from the lockfile
|
||||
if prefer_pipfile and lockfile_version != version and version.startswith("==") and "*" not in version:
|
||||
if (
|
||||
prefer_pipfile
|
||||
and lockfile_version != version
|
||||
and version.startswith("==")
|
||||
and "*" not in version
|
||||
):
|
||||
lockfile_dict["version"] = version
|
||||
lockfile_entry[lockfile_name] = lockfile_dict
|
||||
return lockfile_entry
|
||||
|
||||
+19
-15
@@ -4,11 +4,11 @@ import subprocess
|
||||
import crayons
|
||||
from click import echo as click_echo
|
||||
|
||||
from pipenv.exceptions import PipenvCmdError
|
||||
from pipenv import environments
|
||||
from pipenv.exceptions import PipenvCmdError
|
||||
|
||||
if environments.MYPY_RUNNING:
|
||||
from typing import Tuple
|
||||
from typing import Tuple # noqa
|
||||
|
||||
|
||||
def run_command(cmd, *args, is_verbose=False, **kwargs):
|
||||
@@ -25,6 +25,7 @@ def run_command(cmd, *args, is_verbose=False, **kwargs):
|
||||
|
||||
from pipenv._compat import decode_for_output
|
||||
from pipenv.cmdparse import Script
|
||||
|
||||
catch_exceptions = kwargs.pop("catch_exceptions", True)
|
||||
if isinstance(cmd, ((str,), list, tuple)):
|
||||
cmd = Script.parse(cmd)
|
||||
@@ -38,17 +39,24 @@ def run_command(cmd, *args, is_verbose=False, **kwargs):
|
||||
click_echo(f"Running command: $ {cmd.cmdify()}")
|
||||
c = subprocess_run(command, *args, **kwargs)
|
||||
if is_verbose:
|
||||
click_echo("Command output: {}".format(
|
||||
crayons.cyan(decode_for_output(c.stdout))
|
||||
), err=True)
|
||||
click_echo(
|
||||
"Command output: {}".format(crayons.cyan(decode_for_output(c.stdout))),
|
||||
err=True,
|
||||
)
|
||||
if c.returncode and catch_exceptions:
|
||||
raise PipenvCmdError(cmd.cmdify(), c.stdout, c.stderr, c.returncode)
|
||||
return c
|
||||
|
||||
|
||||
def subprocess_run(
|
||||
args, *, block=True, text=True, capture_output=True,
|
||||
encoding="utf-8", env=None, **other_kwargs
|
||||
args,
|
||||
*,
|
||||
block=True,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
encoding="utf-8",
|
||||
env=None,
|
||||
**other_kwargs,
|
||||
):
|
||||
"""A backward compatible version of subprocess.run().
|
||||
|
||||
@@ -61,17 +69,13 @@ def subprocess_run(
|
||||
_env.update(env)
|
||||
other_kwargs["env"] = _env
|
||||
if capture_output:
|
||||
other_kwargs['stdout'] = subprocess.PIPE
|
||||
other_kwargs['stderr'] = subprocess.PIPE
|
||||
other_kwargs["stdout"] = subprocess.PIPE
|
||||
other_kwargs["stderr"] = subprocess.PIPE
|
||||
if block:
|
||||
return subprocess.run(
|
||||
args, universal_newlines=text,
|
||||
encoding=encoding, **other_kwargs
|
||||
args, universal_newlines=text, encoding=encoding, **other_kwargs
|
||||
)
|
||||
else:
|
||||
return subprocess.Popen(
|
||||
args, universal_newlines=text,
|
||||
encoding=encoding, **other_kwargs
|
||||
args, universal_newlines=text, encoding=encoding, **other_kwargs
|
||||
)
|
||||
|
||||
|
||||
|
||||
+204
-97
@@ -7,27 +7,36 @@ import warnings
|
||||
from functools import lru_cache
|
||||
|
||||
import crayons
|
||||
from pipenv import environments
|
||||
from click import echo as click_echo
|
||||
from pipenv.exceptions import ResolutionFailure, RequirementError
|
||||
from pipenv.vendor.requirementslib import Requirement, Pipfile
|
||||
from pipenv.vendor.vistir import open_file, TemporaryDirectory
|
||||
|
||||
from .dependencies import get_vcs_deps, pep423_name, translate_markers, clean_pkg_version, \
|
||||
is_pinned_requirement, convert_deps_to_pip, HackedPythonVersion
|
||||
from pipenv import environments
|
||||
from pipenv.exceptions import RequirementError, ResolutionFailure
|
||||
from pipenv.vendor.requirementslib import Pipfile, Requirement
|
||||
from pipenv.vendor.requirementslib.models.utils import DIRECT_URL_RE
|
||||
from pipenv.vendor.vistir import TemporaryDirectory, open_file
|
||||
from pipenv.vendor.vistir.path import create_tracked_tempdir
|
||||
|
||||
from .dependencies import (
|
||||
HackedPythonVersion,
|
||||
clean_pkg_version,
|
||||
convert_deps_to_pip,
|
||||
get_vcs_deps,
|
||||
is_pinned_requirement,
|
||||
pep423_name,
|
||||
translate_markers,
|
||||
)
|
||||
from .indexes import parse_indexes, prepare_pip_source_args
|
||||
from .internet import _get_requests_session
|
||||
from .locking import format_requirement_for_lockfile, prepare_lockfile
|
||||
from .shell import temp_environ, subprocess_run, make_posix
|
||||
from .shell import make_posix, subprocess_run, temp_environ
|
||||
from .spinner import create_spinner
|
||||
if environments.MYPY_RUNNING:
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
|
||||
from pipenv.project import Project
|
||||
from pipenv.vendor.requirementslib.models.pipfile import Pipfile
|
||||
from pipenv.vendor.requirementslib.models.requirements import (
|
||||
Line, Requirement
|
||||
)
|
||||
if environments.MYPY_RUNNING:
|
||||
from typing import Any, Dict, List, Optional, Set, Tuple, Union # noqa
|
||||
|
||||
from pipenv.project import Project # noqa
|
||||
from pipenv.vendor.requirementslib import Pipfile, Requirement # noqa
|
||||
from pipenv.vendor.requirementslib.models.requirements import Line # noqa
|
||||
|
||||
|
||||
class HashCacheMixin:
|
||||
@@ -38,6 +47,7 @@ class HashCacheMixin:
|
||||
cache key includes the hash value returned from the server). This ought to
|
||||
avoid issues where the location on the server changes.
|
||||
"""
|
||||
|
||||
def __init__(self, directory, session):
|
||||
self.session = session
|
||||
if not os.path.isdir(directory):
|
||||
@@ -65,8 +75,16 @@ class HashCacheMixin:
|
||||
|
||||
class Resolver:
|
||||
def __init__(
|
||||
self, constraints, req_dir, project, sources, index_lookup=None,
|
||||
markers_lookup=None, skipped=None, clear=False, pre=False
|
||||
self,
|
||||
constraints,
|
||||
req_dir,
|
||||
project,
|
||||
sources,
|
||||
index_lookup=None,
|
||||
markers_lookup=None,
|
||||
skipped=None,
|
||||
clear=False,
|
||||
pre=False,
|
||||
):
|
||||
self.initial_constraints = constraints
|
||||
self.req_dir = req_dir
|
||||
@@ -113,9 +131,9 @@ class Resolver:
|
||||
from pipenv.vendor.pip_shims import shims
|
||||
|
||||
if not self._hash_cache:
|
||||
self._hash_cache = type("HashCache", (HashCacheMixin, shims.SafeFileCache), {})(
|
||||
os.path.join(self.project.s.PIPENV_CACHE_DIR, "hashes"), self.session
|
||||
)
|
||||
self._hash_cache = type(
|
||||
"HashCache", (HashCacheMixin, shims.SafeFileCache), {}
|
||||
)(os.path.join(self.project.s.PIPENV_CACHE_DIR, "hashes"), self.session)
|
||||
return self._hash_cache
|
||||
|
||||
@classmethod
|
||||
@@ -132,23 +150,31 @@ class Resolver:
|
||||
):
|
||||
# type: (...) -> Tuple[Set[str], Dict[str, Dict[str, Union[str, bool, List[str]]]], Dict[str, str], Dict[str, str]]
|
||||
constraints = set() # type: Set[str]
|
||||
skipped = dict() # type: Dict[str, Dict[str, Union[str, bool, List[str]]]]
|
||||
skipped = {} # type: Dict[str, Dict[str, Union[str, bool, List[str]]]]
|
||||
if index_lookup is None:
|
||||
index_lookup = {}
|
||||
if markers_lookup is None:
|
||||
markers_lookup = {}
|
||||
if not req_dir:
|
||||
from pipenv.vendor.vistir.path import create_tracked_tempdir
|
||||
req_dir = create_tracked_tempdir(prefix="pipenv-", suffix="-reqdir")
|
||||
transient_resolver = cls(
|
||||
[], req_dir, project, sources, index_lookup=index_lookup,
|
||||
markers_lookup=markers_lookup, clear=clear, pre=pre
|
||||
[],
|
||||
req_dir,
|
||||
project,
|
||||
sources,
|
||||
index_lookup=index_lookup,
|
||||
markers_lookup=markers_lookup,
|
||||
clear=clear,
|
||||
pre=pre,
|
||||
)
|
||||
for dep in deps:
|
||||
if not dep:
|
||||
continue
|
||||
req, req_idx, markers_idx = cls.parse_line(
|
||||
dep, index_lookup=index_lookup, markers_lookup=markers_lookup, project=project
|
||||
dep,
|
||||
index_lookup=index_lookup,
|
||||
markers_lookup=markers_lookup,
|
||||
project=project,
|
||||
)
|
||||
index_lookup.update(req_idx)
|
||||
markers_lookup.update(markers_idx)
|
||||
@@ -158,12 +184,20 @@ class Resolver:
|
||||
# to the lockfile directly
|
||||
use_sources = None
|
||||
if req.name in index_lookup:
|
||||
use_sources = list(filter(lambda s: s.get('name') == index_lookup[req.name], sources))
|
||||
use_sources = list(
|
||||
filter(lambda s: s.get("name") == index_lookup[req.name], sources)
|
||||
)
|
||||
if not use_sources:
|
||||
use_sources = sources
|
||||
transient_resolver = cls(
|
||||
[], req_dir, project, use_sources, index_lookup=index_lookup,
|
||||
markers_lookup=markers_lookup, clear=clear, pre=pre
|
||||
[],
|
||||
req_dir,
|
||||
project,
|
||||
use_sources,
|
||||
index_lookup=index_lookup,
|
||||
markers_lookup=markers_lookup,
|
||||
clear=clear,
|
||||
pre=pre,
|
||||
)
|
||||
constraint_update, lockfile_update = cls.get_deps_from_req(
|
||||
req, resolver=transient_resolver, resolve_vcs=project.s.PIPENV_RESOLVE_VCS
|
||||
@@ -178,17 +212,17 @@ class Resolver:
|
||||
line, # type: str
|
||||
index_lookup=None, # type: Dict[str, str]
|
||||
markers_lookup=None, # type: Dict[str, str]
|
||||
project=None # type: Optional[Project]
|
||||
project=None, # type: Optional[Project]
|
||||
):
|
||||
# type: (...) -> Tuple[Requirement, Dict[str, str], Dict[str, str]]
|
||||
from pipenv.vendor.requirementslib.models.requirements import Requirement
|
||||
from pipenv.vendor.requirementslib.models.utils import DIRECT_URL_RE
|
||||
|
||||
if index_lookup is None:
|
||||
index_lookup = {}
|
||||
if markers_lookup is None:
|
||||
markers_lookup = {}
|
||||
if project is None:
|
||||
from pipenv.project import Project
|
||||
|
||||
project = Project()
|
||||
index, extra_index, trust_host, remainder = parse_indexes(line)
|
||||
line = " ".join(remainder)
|
||||
@@ -202,13 +236,18 @@ class Resolver:
|
||||
try:
|
||||
req = Requirement.from_line(line)
|
||||
except ValueError:
|
||||
raise ResolutionFailure(f"Failed to resolve requirement from line: {line!s}")
|
||||
raise ResolutionFailure(
|
||||
f"Failed to resolve requirement from line: {line!s}"
|
||||
)
|
||||
else:
|
||||
raise ResolutionFailure(f"Failed to resolve requirement from line: {line!s}")
|
||||
raise ResolutionFailure(
|
||||
f"Failed to resolve requirement from line: {line!s}"
|
||||
)
|
||||
if index:
|
||||
try:
|
||||
index_lookup[req.normalized_name] = project.get_source(
|
||||
url=index, refresh=True).get("name")
|
||||
url=index, refresh=True
|
||||
).get("name")
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
@@ -227,13 +266,13 @@ class Resolver:
|
||||
# type: (Requirement, Optional["Resolver"], bool) -> Tuple[Set[str], Dict[str, Dict[str, Union[str, bool, List[str]]]]]
|
||||
from pipenv.vendor.requirementslib.models.requirements import Requirement
|
||||
from pipenv.vendor.requirementslib.models.utils import (
|
||||
_requirement_to_str_lowercase_name
|
||||
_requirement_to_str_lowercase_name,
|
||||
)
|
||||
from pipenv.vendor.requirementslib.utils import is_installable_dir
|
||||
|
||||
# TODO: this is way too complex, refactor this
|
||||
constraints = set() # type: Set[str]
|
||||
locked_deps = dict() # type: Dict[str, Dict[str, Union[str, bool, List[str]]]]
|
||||
locked_deps = {} # type: Dict[str, Dict[str, Union[str, bool, List[str]]]]
|
||||
if (req.is_file_or_url or req.is_vcs) and not req.is_wheel:
|
||||
# for local packages with setup.py files and potential direct url deps:
|
||||
if req.is_vcs:
|
||||
@@ -243,7 +282,6 @@ class Resolver:
|
||||
else:
|
||||
_, entry = req.pipfile_entry
|
||||
parsed_line = req.req.parsed_line # type: Line
|
||||
setup_info = None # type: Any
|
||||
try:
|
||||
name = req.normalized_name
|
||||
except TypeError:
|
||||
@@ -255,8 +293,11 @@ class Resolver:
|
||||
# Allow users to toggle resolution off for non-editable VCS packages
|
||||
# but leave it on for local, installable folders on the filesystem
|
||||
if resolve_vcs or (
|
||||
req.editable or parsed_line.is_wheel or (
|
||||
req.is_file_or_url and parsed_line.is_local
|
||||
req.editable
|
||||
or parsed_line.is_wheel
|
||||
or (
|
||||
req.is_file_or_url
|
||||
and parsed_line.is_local
|
||||
and is_installable_dir(parsed_line.path)
|
||||
)
|
||||
):
|
||||
@@ -271,9 +312,7 @@ class Resolver:
|
||||
if r.marker and not r.marker.evaluate():
|
||||
new_constraints = {}
|
||||
_, new_entry = req.pipfile_entry
|
||||
new_lock = {
|
||||
pep423_name(new_req.normalized_name): new_entry
|
||||
}
|
||||
new_lock = {pep423_name(new_req.normalized_name): new_entry}
|
||||
else:
|
||||
new_constraints, new_lock = cls.get_deps_from_req(
|
||||
new_req, resolver
|
||||
@@ -298,14 +337,22 @@ class Resolver:
|
||||
else:
|
||||
# if the dependency isn't installable, don't add it to constraints
|
||||
# and instead add it directly to the lock
|
||||
if req and req.requirement and (
|
||||
req.requirement.marker and not req.requirement.marker.evaluate()
|
||||
if (
|
||||
req
|
||||
and req.requirement
|
||||
and (req.requirement.marker and not req.requirement.marker.evaluate())
|
||||
):
|
||||
pypi = resolver.finder if resolver else None
|
||||
ireq = req.ireq
|
||||
best_match = pypi.find_best_candidate(ireq.name, ireq.specifier).best_candidate if pypi else None
|
||||
best_match = (
|
||||
pypi.find_best_candidate(ireq.name, ireq.specifier).best_candidate
|
||||
if pypi
|
||||
else None
|
||||
)
|
||||
if best_match:
|
||||
ireq.req.specifier = ireq.specifier.__class__(f"=={best_match.version}")
|
||||
ireq.req.specifier = ireq.specifier.__class__(
|
||||
f"=={best_match.version}"
|
||||
)
|
||||
hashes = resolver.collect_hashes(ireq) if resolver else []
|
||||
new_req = Requirement.from_ireq(ireq)
|
||||
new_req = new_req.add_hashes(hashes)
|
||||
@@ -314,13 +361,13 @@ class Resolver:
|
||||
click_echo(
|
||||
"{} doesn't match your environment, "
|
||||
"its dependencies won't be resolved.".format(req.as_line()),
|
||||
err=True
|
||||
err=True,
|
||||
)
|
||||
else:
|
||||
click_echo(
|
||||
"Could not find a version of {} that matches your environment, "
|
||||
"it will be skipped.".format(req.as_line()),
|
||||
err=True
|
||||
err=True,
|
||||
)
|
||||
return constraints, locked_deps
|
||||
constraints.add(req.constraint_line)
|
||||
@@ -337,10 +384,10 @@ class Resolver:
|
||||
sources=None, # type: List[str]
|
||||
req_dir=None, # type: str
|
||||
clear=False, # type: bool
|
||||
pre=False # type: bool
|
||||
pre=False, # type: bool
|
||||
):
|
||||
# type: (...) -> "Resolver"
|
||||
from pipenv.vendor.vistir.path import create_tracked_tempdir
|
||||
|
||||
if not req_dir:
|
||||
req_dir = create_tracked_tempdir(suffix="-requirements", prefix="pipenv-")
|
||||
if index_lookup is None:
|
||||
@@ -350,18 +397,31 @@ class Resolver:
|
||||
if sources is None:
|
||||
sources = project.sources
|
||||
constraints, skipped, index_lookup, markers_lookup = cls.get_metadata(
|
||||
deps, index_lookup, markers_lookup, project, sources, req_dir=req_dir,
|
||||
pre=pre, clear=clear
|
||||
deps,
|
||||
index_lookup,
|
||||
markers_lookup,
|
||||
project,
|
||||
sources,
|
||||
req_dir=req_dir,
|
||||
pre=pre,
|
||||
clear=clear,
|
||||
)
|
||||
return Resolver(
|
||||
constraints, req_dir, project, sources, index_lookup=index_lookup,
|
||||
markers_lookup=markers_lookup, skipped=skipped, clear=clear, pre=pre
|
||||
constraints,
|
||||
req_dir,
|
||||
project,
|
||||
sources,
|
||||
index_lookup=index_lookup,
|
||||
markers_lookup=markers_lookup,
|
||||
skipped=skipped,
|
||||
clear=clear,
|
||||
pre=pre,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_pipfile(cls, project, pipfile=None, dev=False, pre=False, clear=False):
|
||||
# type: (Optional[Project], Optional[Pipfile], bool, bool, bool) -> "Resolver"
|
||||
from pipenv.vendor.vistir.path import create_tracked_tempdir
|
||||
|
||||
if not pipfile:
|
||||
pipfile = project._pipfile
|
||||
req_dir = create_tracked_tempdir(suffix="-requirements", prefix="pipenv-")
|
||||
@@ -371,12 +431,25 @@ class Resolver:
|
||||
deps.update({req.as_line() for req in pipfile.dev_packages})
|
||||
deps.update({req.as_line() for req in pipfile.packages})
|
||||
constraints, skipped, index_lookup, markers_lookup = cls.get_metadata(
|
||||
list(deps), index_lookup, markers_lookup, project, project.sources,
|
||||
req_dir=req_dir, pre=pre, clear=clear
|
||||
list(deps),
|
||||
index_lookup,
|
||||
markers_lookup,
|
||||
project,
|
||||
project.sources,
|
||||
req_dir=req_dir,
|
||||
pre=pre,
|
||||
clear=clear,
|
||||
)
|
||||
return Resolver(
|
||||
constraints, req_dir, project, project.sources, index_lookup=index_lookup,
|
||||
markers_lookup=markers_lookup, skipped=skipped, clear=clear, pre=pre
|
||||
constraints,
|
||||
req_dir,
|
||||
project,
|
||||
project.sources,
|
||||
index_lookup=index_lookup,
|
||||
markers_lookup=markers_lookup,
|
||||
skipped=skipped,
|
||||
clear=clear,
|
||||
pre=pre,
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -410,6 +483,7 @@ class Resolver:
|
||||
|
||||
def prepare_constraint_file(self):
|
||||
from pipenv.vendor.vistir.path import create_tracked_tempfile
|
||||
|
||||
constraints_file = create_tracked_tempfile(
|
||||
mode="w",
|
||||
prefix="pipenv-",
|
||||
@@ -419,7 +493,8 @@ class Resolver:
|
||||
)
|
||||
skip_args = ("build-isolation", "use-pep517", "cache-dir")
|
||||
args_to_add = [
|
||||
arg for arg in self.pip_args
|
||||
arg
|
||||
for arg in self.pip_args
|
||||
if not any(bad_arg in arg for bad_arg in skip_args)
|
||||
]
|
||||
if self.sources:
|
||||
@@ -446,7 +521,9 @@ class Resolver:
|
||||
pip_options.no_input = True
|
||||
pip_options.progress_bar = "off"
|
||||
pip_options.ignore_requires_python = True
|
||||
pip_options.pre = self.pre or self.project.settings.get("allow_prereleases", False)
|
||||
pip_options.pre = self.pre or self.project.settings.get(
|
||||
"allow_prereleases", False
|
||||
)
|
||||
self._pip_options = pip_options
|
||||
return self._pip_options
|
||||
|
||||
@@ -459,16 +536,17 @@ class Resolver:
|
||||
@property
|
||||
def finder(self):
|
||||
from pipenv.vendor.pip_shims import shims
|
||||
|
||||
if self._finder is None:
|
||||
self._finder = shims.get_package_finder(
|
||||
install_cmd=self.pip_command,
|
||||
options=self.pip_options,
|
||||
session=self.session
|
||||
session=self.session,
|
||||
)
|
||||
index_mapping = {}
|
||||
for source in self.sources:
|
||||
if source.get('name'):
|
||||
index_mapping[source['name']] = source['url']
|
||||
if source.get("name"):
|
||||
index_mapping[source["name"]] = source["url"]
|
||||
alt_index_lookup = {}
|
||||
for req_name, index in self.index_lookup.items():
|
||||
if index_mapping.get(index):
|
||||
@@ -480,6 +558,7 @@ class Resolver:
|
||||
@property
|
||||
def ignore_compatibility_finder(self):
|
||||
from pipenv.vendor.pip_shims import shims
|
||||
|
||||
if self._ignore_compatibility_finder is None:
|
||||
ignore_compatibility_finder = shims.get_package_finder(
|
||||
install_cmd=self.pip_command,
|
||||
@@ -501,20 +580,26 @@ class Resolver:
|
||||
pip_options.extra_index_urls = []
|
||||
if self._parsed_constraints is None:
|
||||
self._parsed_constraints = shims.parse_requirements(
|
||||
self.constraint_file, finder=self.finder, session=self.session,
|
||||
options=pip_options
|
||||
self.constraint_file,
|
||||
finder=self.finder,
|
||||
session=self.session,
|
||||
options=pip_options,
|
||||
)
|
||||
return self._parsed_constraints
|
||||
|
||||
@property
|
||||
def constraints(self):
|
||||
from pipenv.patched.notpip._internal.req.constructors import install_req_from_parsed_requirement
|
||||
from pipenv.patched.notpip._internal.req.constructors import (
|
||||
install_req_from_parsed_requirement,
|
||||
)
|
||||
|
||||
if self._constraints is None:
|
||||
self._constraints = [
|
||||
install_req_from_parsed_requirement(
|
||||
c, isolated=self.pip_options.build_isolation,
|
||||
use_pep517=self.pip_options.use_pep517, user_supplied=True
|
||||
c,
|
||||
isolated=self.pip_options.build_isolation,
|
||||
use_pep517=self.pip_options.use_pep517,
|
||||
user_supplied=True,
|
||||
)
|
||||
for c in self.parsed_constraints
|
||||
]
|
||||
@@ -523,10 +608,14 @@ class Resolver:
|
||||
@contextlib.contextmanager
|
||||
def get_resolver(self, clear=False):
|
||||
from pipenv.vendor.pip_shims.shims import (
|
||||
WheelCache, get_requirement_tracker, global_tempdir_manager
|
||||
WheelCache,
|
||||
get_requirement_tracker,
|
||||
global_tempdir_manager,
|
||||
)
|
||||
|
||||
with global_tempdir_manager(), get_requirement_tracker() as req_tracker, TemporaryDirectory(suffix="-build", prefix="pipenv-") as directory:
|
||||
with global_tempdir_manager(), get_requirement_tracker() as req_tracker, TemporaryDirectory(
|
||||
suffix="-build", prefix="pipenv-"
|
||||
) as directory:
|
||||
pip_options = self.pip_options
|
||||
finder = self.finder
|
||||
wheel_cache = WheelCache(pip_options.cache_dir, pip_options.format_control)
|
||||
@@ -554,8 +643,8 @@ class Resolver:
|
||||
yield resolver
|
||||
|
||||
def resolve(self):
|
||||
from pipenv.vendor.pip_shims.shims import InstallationError
|
||||
from pipenv.exceptions import ResolutionFailure
|
||||
from pipenv.vendor.pip_shims.shims import InstallationError
|
||||
|
||||
self.constraints # For some reason it is important to evaluate constraints before resolver context
|
||||
with temp_environ(), self.get_resolver() as resolver:
|
||||
@@ -570,12 +659,15 @@ class Resolver:
|
||||
|
||||
def resolve_constraints(self):
|
||||
from pipenv.vendor.requirementslib.models.markers import marker_from_specifier
|
||||
|
||||
new_tree = set()
|
||||
for result in self.resolved_tree:
|
||||
if result.markers:
|
||||
self.markers[result.name] = result.markers
|
||||
else:
|
||||
candidate = self.finder.find_best_candidate(result.name, result.specifier).best_candidate
|
||||
candidate = self.finder.find_best_candidate(
|
||||
result.name, result.specifier
|
||||
).best_candidate
|
||||
if candidate:
|
||||
requires_python = candidate.link.requires_python
|
||||
if requires_python:
|
||||
@@ -625,7 +717,8 @@ class Resolver:
|
||||
click_echo(
|
||||
"{}: Error generating hash for {}".format(
|
||||
crayons.red("Warning", bold=True), ireq.name
|
||||
), err=True
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
return None
|
||||
|
||||
@@ -688,13 +781,12 @@ class Resolver:
|
||||
return req.name, entry
|
||||
|
||||
def clean_results(self):
|
||||
from pipenv.vendor.requirementslib.models.requirements import (
|
||||
Requirement
|
||||
)
|
||||
from pipenv.vendor.requirementslib.models.requirements import Requirement
|
||||
|
||||
reqs = [(Requirement.from_ireq(ireq), ireq) for ireq in self.resolved_tree]
|
||||
results = {}
|
||||
for req, ireq in reqs:
|
||||
if (req.vcs and req.editable and not req.is_direct_url):
|
||||
if req.vcs and req.editable and not req.is_direct_url:
|
||||
continue
|
||||
elif req.normalized_name in self.skipped.keys():
|
||||
continue
|
||||
@@ -723,8 +815,14 @@ class Resolver:
|
||||
|
||||
|
||||
def _show_warning(message, category, filename, lineno, line):
|
||||
warnings.showwarning(message=message, category=category, filename=filename,
|
||||
lineno=lineno, file=sys.stderr, line=line)
|
||||
warnings.showwarning(
|
||||
message=message,
|
||||
category=category,
|
||||
filename=filename,
|
||||
lineno=lineno,
|
||||
file=sys.stderr,
|
||||
line=line,
|
||||
)
|
||||
sys.stderr.flush()
|
||||
|
||||
|
||||
@@ -738,8 +836,6 @@ def actually_resolve_deps(
|
||||
pre,
|
||||
req_dir=None,
|
||||
):
|
||||
from pipenv.vendor.vistir.path import create_tracked_tempdir
|
||||
|
||||
if not req_dir:
|
||||
req_dir = create_tracked_tempdir(suffix="-requirements", prefix="pipenv-")
|
||||
warning_list = []
|
||||
@@ -753,8 +849,13 @@ def actually_resolve_deps(
|
||||
resolver.resolve_constraints()
|
||||
results = resolver.clean_results()
|
||||
for warning in warning_list:
|
||||
_show_warning(warning.message, warning.category, warning.filename, warning.lineno,
|
||||
warning.line)
|
||||
_show_warning(
|
||||
warning.message,
|
||||
warning.category,
|
||||
warning.filename,
|
||||
warning.lineno,
|
||||
warning.line,
|
||||
)
|
||||
return (results, hashes, resolver.markers_lookup, resolver, resolver.skipped)
|
||||
|
||||
|
||||
@@ -762,6 +863,7 @@ def resolve(cmd, sp, project):
|
||||
from pipenv._compat import decode_output
|
||||
from pipenv.cmdparse import Script
|
||||
from pipenv.vendor.vistir.misc import echo
|
||||
|
||||
c = subprocess_run(Script.parse(cmd).cmd_args, block=False, env=os.environ.copy())
|
||||
is_verbose = project.s.is_verbose()
|
||||
err = ""
|
||||
@@ -777,9 +879,7 @@ def resolve(cmd, sp, project):
|
||||
returncode = c.poll()
|
||||
out = c.stdout.read()
|
||||
if returncode != 0:
|
||||
sp.red.fail(environments.PIPENV_SPINNER_FAIL_TEXT.format(
|
||||
"Locking Failed!"
|
||||
))
|
||||
sp.red.fail(environments.PIPENV_SPINNER_FAIL_TEXT.format("Locking Failed!"))
|
||||
echo(out.strip(), err=True)
|
||||
if not is_verbose:
|
||||
echo(err, err=True)
|
||||
@@ -800,7 +900,7 @@ def venv_resolve_deps(
|
||||
dev=False,
|
||||
pipfile=None,
|
||||
lockfile=None,
|
||||
keep_outdated=False
|
||||
keep_outdated=False,
|
||||
):
|
||||
"""
|
||||
Resolve dependencies for a pipenv project, acts as a portal to the target environment.
|
||||
@@ -833,7 +933,6 @@ def venv_resolve_deps(
|
||||
from pipenv._compat import decode_for_output
|
||||
from pipenv.vendor.vistir.compat import JSONDecodeError, NamedTemporaryFile, Path
|
||||
from pipenv.vendor.vistir.misc import fs_str
|
||||
from pipenv.vendor.vistir.path import create_tracked_tempdir
|
||||
|
||||
results = []
|
||||
pipfile_section = "dev-packages" if dev else "packages"
|
||||
@@ -852,7 +951,7 @@ def venv_resolve_deps(
|
||||
req_dir = create_tracked_tempdir(prefix="pipenv", suffix="requirements")
|
||||
cmd = [
|
||||
which("python", allow_global=allow_global),
|
||||
Path(resolver.__file__.rstrip("co")).as_posix()
|
||||
Path(resolver.__file__.rstrip("co")).as_posix(),
|
||||
]
|
||||
if pre:
|
||||
cmd.append("--pre")
|
||||
@@ -879,15 +978,15 @@ def venv_resolve_deps(
|
||||
os.environ.pop("PIPENV_SITE_DIR", None)
|
||||
if keep_outdated:
|
||||
os.environ["PIPENV_KEEP_OUTDATED"] = fs_str("1")
|
||||
with create_spinner(text=decode_for_output("Locking..."), setting=project.s) as sp:
|
||||
with create_spinner(
|
||||
text=decode_for_output("Locking..."), setting=project.s
|
||||
) as sp:
|
||||
# This conversion is somewhat slow on local and file-type requirements since
|
||||
# we now download those requirements / make temporary folders to perform
|
||||
# dependency resolution on them, so we are including this step inside the
|
||||
# spinner context manager for the UX improvement
|
||||
sp.write(decode_for_output("Building requirements..."))
|
||||
deps = convert_deps_to_pip(
|
||||
deps, project, r=False, include_index=True
|
||||
)
|
||||
deps = convert_deps_to_pip(deps, project, r=False, include_index=True)
|
||||
constraints = set(deps)
|
||||
os.environ["PIPENV_PACKAGES"] = str("\n".join(constraints))
|
||||
sp.write(decode_for_output("Resolving dependencies..."))
|
||||
@@ -898,7 +997,9 @@ def venv_resolve_deps(
|
||||
if not project.s.is_verbose() and c.stderr.strip():
|
||||
click_echo(crayons.yellow(f"Warning: {c.stderr.strip()}"), err=True)
|
||||
else:
|
||||
sp.red.fail(environments.PIPENV_SPINNER_FAIL_TEXT.format("Locking Failed!"))
|
||||
sp.red.fail(
|
||||
environments.PIPENV_SPINNER_FAIL_TEXT.format("Locking Failed!")
|
||||
)
|
||||
click_echo(f"Output: {c.stdout.strip()}", err=True)
|
||||
click_echo(f"Error: {c.stderr.strip()}", err=True)
|
||||
try:
|
||||
@@ -926,7 +1027,7 @@ def resolve_deps(
|
||||
clear=False,
|
||||
pre=False,
|
||||
allow_global=False,
|
||||
req_dir=None
|
||||
req_dir=None,
|
||||
):
|
||||
"""Given a list of dependencies, return a resolved list of dependencies,
|
||||
using pip-tools -- and their hashes, using the warehouse API / pip.
|
||||
@@ -944,7 +1045,6 @@ def resolve_deps(
|
||||
# First (proper) attempt:
|
||||
req_dir = req_dir if req_dir else os.environ.get("req_dir", None)
|
||||
if not req_dir:
|
||||
from pipenv.vendor.vistir.path import create_tracked_tempdir
|
||||
req_dir = create_tracked_tempdir(prefix="pipenv-", suffix="-requirements")
|
||||
with HackedPythonVersion(python_version=python, python_path=python_path):
|
||||
try:
|
||||
@@ -970,7 +1070,13 @@ def resolve_deps(
|
||||
try:
|
||||
# Attempt to resolve again, with different Python version information,
|
||||
# particularly for particularly particular packages.
|
||||
results, hashes, markers_lookup, resolver, skipped = actually_resolve_deps(
|
||||
(
|
||||
results,
|
||||
hashes,
|
||||
markers_lookup,
|
||||
resolver,
|
||||
skipped,
|
||||
) = actually_resolve_deps(
|
||||
deps,
|
||||
index_lookup,
|
||||
markers_lookup,
|
||||
@@ -989,6 +1095,7 @@ def resolve_deps(
|
||||
def get_pipenv_sitedir():
|
||||
# type: () -> Optional[str]
|
||||
import pkg_resources
|
||||
|
||||
site_dir = next(
|
||||
iter(d for d in pkg_resources.working_set if d.key.lower() == "pipenv"), None
|
||||
)
|
||||
|
||||
+32
-24
@@ -1,5 +1,6 @@
|
||||
import errno
|
||||
import os
|
||||
import posixpath
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
@@ -8,17 +9,16 @@ import sys
|
||||
import warnings
|
||||
from contextlib import contextmanager
|
||||
from functools import lru_cache
|
||||
import posixpath
|
||||
from pathlib import Path
|
||||
|
||||
from .constants import SCHEME_LIST
|
||||
from .processes import subprocess_run
|
||||
from pipenv import environments
|
||||
from pipenv.vendor.vistir.compat import ResourceWarning
|
||||
|
||||
from .constants import SCHEME_LIST
|
||||
from .processes import subprocess_run
|
||||
|
||||
if environments.MYPY_RUNNING:
|
||||
from typing import Text
|
||||
from typing import Text # noqa
|
||||
|
||||
|
||||
@lru_cache()
|
||||
@@ -51,6 +51,7 @@ def make_posix(path):
|
||||
|
||||
def get_pipenv_dist(pkg="pipenv", pipenv_site=None):
|
||||
from pipenv.resolver import find_site_path
|
||||
|
||||
pipenv_libdir = os.path.dirname(os.path.abspath(__file__))
|
||||
if pipenv_site is None:
|
||||
pipenv_site = os.path.dirname(pipenv_libdir)
|
||||
@@ -80,8 +81,8 @@ def looks_like_dir(path):
|
||||
|
||||
def load_path(python):
|
||||
import json
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
python = Path(python).as_posix()
|
||||
json_dump_commmand = '"import json, sys; print(json.dumps(sys.path));"'
|
||||
c = subprocess_run([python, "-c", json_dump_commmand])
|
||||
@@ -96,9 +97,9 @@ def path_to_url(path):
|
||||
|
||||
|
||||
def normalize_path(path):
|
||||
return os.path.expandvars(os.path.expanduser(
|
||||
os.path.normcase(os.path.normpath(os.path.abspath(str(path))))
|
||||
))
|
||||
return os.path.expandvars(
|
||||
os.path.expanduser(os.path.normcase(os.path.normpath(os.path.abspath(str(path)))))
|
||||
)
|
||||
|
||||
|
||||
def get_windows_path(*args):
|
||||
@@ -157,7 +158,7 @@ def walk_up(bottom):
|
||||
def find_requirements(max_depth=3):
|
||||
"""Returns the path of a requirements.txt file in parent directories."""
|
||||
i = 0
|
||||
for c, d, f in walk_up(os.getcwd()):
|
||||
for c, _, _ in walk_up(os.getcwd()):
|
||||
i += 1
|
||||
if i < max_depth:
|
||||
r = os.path.join(c, "requirements.txt")
|
||||
@@ -183,13 +184,12 @@ def temp_environ():
|
||||
|
||||
def escape_cmd(cmd):
|
||||
if any(special_char in cmd for special_char in ["<", ">", "&", ".", "^", "|", "?"]):
|
||||
cmd = f'\"{cmd}\"'
|
||||
cmd = f'"{cmd}"'
|
||||
return cmd
|
||||
|
||||
|
||||
def safe_expandvars(value):
|
||||
"""Call os.path.expandvars if value is a string, otherwise do nothing.
|
||||
"""
|
||||
"""Call os.path.expandvars if value is a string, otherwise do nothing."""
|
||||
if isinstance(value, str):
|
||||
return os.path.expandvars(value)
|
||||
return value
|
||||
@@ -239,8 +239,8 @@ def is_virtual_environment(path):
|
||||
"""
|
||||
if not path.is_dir():
|
||||
return False
|
||||
for bindir_name in ('bin', 'Scripts'):
|
||||
for python in path.joinpath(bindir_name).glob('python*'):
|
||||
for bindir_name in ("bin", "Scripts"):
|
||||
for python in path.joinpath(bindir_name).glob("python*"):
|
||||
try:
|
||||
exeness = python.is_file() and os.access(str(python), os.X_OK)
|
||||
except OSError:
|
||||
@@ -252,10 +252,17 @@ def is_virtual_environment(path):
|
||||
|
||||
def mkdir_p(newdir):
|
||||
"""works the way a good mkdir should :)
|
||||
<<<<<<< HEAD
|
||||
- already exists, silently complete
|
||||
- regular file in the way, raise an exception
|
||||
- parent directory(ies) does not exist, make them as well
|
||||
From: http://code.activestate.com/recipes/82465-a-friendly-mkdir/
|
||||
=======
|
||||
- already exists, silently complete
|
||||
- regular file in the way, raise an exception
|
||||
- parent directory(ies) does not exist, make them as well
|
||||
From: http://code.activestate.com/recipes/82465-a-friendly-mkdir/
|
||||
>>>>>>> main
|
||||
"""
|
||||
if os.path.isdir(newdir):
|
||||
pass
|
||||
@@ -295,19 +302,18 @@ def find_python(finder, line=None):
|
||||
"""
|
||||
|
||||
if line and not isinstance(line, str):
|
||||
raise TypeError(
|
||||
f"Invalid python search type: expected string, received {line!r}"
|
||||
)
|
||||
raise TypeError(f"Invalid python search type: expected string, received {line!r}")
|
||||
if line and os.path.isabs(line):
|
||||
if os.name == "nt":
|
||||
line = make_posix(line)
|
||||
return line
|
||||
if not finder:
|
||||
from pipenv.vendor.pythonfinder import Finder
|
||||
|
||||
finder = Finder(global_search=True)
|
||||
if not line:
|
||||
result = next(iter(finder.find_all_python_versions()), None)
|
||||
elif line and line[0].isdigit() or re.match(r'[\d\.]+', line):
|
||||
elif line and line[0].isdigit() or re.match(r"[\d\.]+", line):
|
||||
result = finder.find_python_version(line)
|
||||
else:
|
||||
result = finder.find_python_version(name=line)
|
||||
@@ -339,9 +345,13 @@ def is_python_command(line):
|
||||
raise TypeError(f"Not a valid command to check: {line!r}")
|
||||
|
||||
from pipenv.vendor.pythonfinder.utils import PYTHON_IMPLEMENTATIONS
|
||||
is_version = re.match(r'\d+(\.\d+)*', line)
|
||||
if (line.startswith("python") or is_version
|
||||
or any(line.startswith(v) for v in PYTHON_IMPLEMENTATIONS)):
|
||||
|
||||
is_version = re.match(r"\d+(\.\d+)*", line)
|
||||
if (
|
||||
line.startswith("python")
|
||||
or is_version
|
||||
or any(line.startswith(v) for v in PYTHON_IMPLEMENTATIONS)
|
||||
):
|
||||
return True
|
||||
# we are less sure about this but we can guess
|
||||
if line.startswith("py"):
|
||||
@@ -405,9 +415,7 @@ def handle_remove_readonly(func, path, exc):
|
||||
Windows source repo folders are read-only by default, so this error handler
|
||||
attempts to set them as writeable and then proceed with deletion."""
|
||||
# Check for read-only attribute
|
||||
default_warning_message = (
|
||||
"Unable to remove file due to permissions restriction: {!r}"
|
||||
)
|
||||
default_warning_message = "Unable to remove file due to permissions restriction: {!r}"
|
||||
# split the initial exception out into its type, exception, and traceback
|
||||
exc_type, exc_exception, exc_tb = exc
|
||||
if is_readonly_path(path):
|
||||
|
||||
@@ -5,6 +5,7 @@ import contextlib
|
||||
def create_spinner(text, setting, nospin=None, spinner_name=None):
|
||||
from pipenv.vendor.vistir import spin
|
||||
from pipenv.vendor.vistir.misc import fs_str
|
||||
|
||||
if not spinner_name:
|
||||
spinner_name = setting.PIPENV_SPINNER
|
||||
if nospin is None:
|
||||
@@ -12,6 +13,7 @@ def create_spinner(text, setting, nospin=None, spinner_name=None):
|
||||
with spin.create_spinner(
|
||||
spinner_name=spinner_name,
|
||||
start_text=fs_str(text),
|
||||
nospin=nospin, write_to_stdout=False
|
||||
nospin=nospin,
|
||||
write_to_stdout=False,
|
||||
) as sp:
|
||||
yield sp
|
||||
|
||||
@@ -27,6 +27,7 @@ def cleanup_toml(tml):
|
||||
|
||||
def convert_toml_outline_tables(parsed):
|
||||
"""Converts all outline tables to inline tables."""
|
||||
|
||||
def convert_tomlkit_table(section):
|
||||
if isinstance(section, tomlkit.items.Table):
|
||||
body = section.value._body
|
||||
@@ -35,14 +36,18 @@ def convert_toml_outline_tables(parsed):
|
||||
for key, value in body:
|
||||
if not key:
|
||||
continue
|
||||
if hasattr(value, "keys") and not isinstance(value, tomlkit.items.InlineTable):
|
||||
if hasattr(value, "keys") and not isinstance(
|
||||
value, tomlkit.items.InlineTable
|
||||
):
|
||||
table = tomlkit.inline_table()
|
||||
table.update(value.value)
|
||||
section[key.key] = table
|
||||
|
||||
def convert_toml_table(section):
|
||||
for package, value in section.items():
|
||||
if hasattr(value, "keys") and not isinstance(value, toml.decoder.InlineTableDict):
|
||||
if hasattr(value, "keys") and not isinstance(
|
||||
value, toml.decoder.InlineTableDict
|
||||
):
|
||||
table = toml.TomlDecoder().get_empty_inline_table()
|
||||
table.update(value)
|
||||
section[package] = table
|
||||
|
||||
@@ -70,3 +70,8 @@ template = "news/towncrier_template.rst"
|
||||
directory = "removal"
|
||||
name = "Removals and Deprecations"
|
||||
showcontent = true
|
||||
|
||||
[[tool.towncrier.type]]
|
||||
directory = "process"
|
||||
name = "Relates to dev process changes"
|
||||
showcontent = true
|
||||
|
||||
@@ -4,7 +4,7 @@ import os
|
||||
import sys
|
||||
from shutil import rmtree
|
||||
|
||||
from setuptools import find_packages, setup, Command
|
||||
from setuptools import Command, find_packages, setup
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
@@ -25,7 +25,7 @@ required = [
|
||||
"certifi",
|
||||
"setuptools>=36.2.1",
|
||||
"virtualenv-clone>=0.2.5",
|
||||
"virtualenv"
|
||||
"virtualenv",
|
||||
]
|
||||
extras = {
|
||||
"dev": [
|
||||
@@ -113,7 +113,7 @@ setup(
|
||||
version=about["__version__"],
|
||||
description="Python Development Workflow for Humans.",
|
||||
long_description=long_description,
|
||||
long_description_content_type='text/markdown',
|
||||
long_description_content_type="text/markdown",
|
||||
author="Pipenv maintainer team",
|
||||
author_email="distutils-sig@python.org",
|
||||
url="https://github.com/pypa/pipenv",
|
||||
|
||||
@@ -6,7 +6,6 @@ import invoke
|
||||
|
||||
from . import release, vendoring
|
||||
|
||||
|
||||
ROOT = Path(".").parent.parent.absolute()
|
||||
|
||||
ns = invoke.Collection(vendoring, release, release.clean_mdchangelog)
|
||||
|
||||
+24
-21
@@ -2,11 +2,10 @@ import datetime
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import invoke
|
||||
|
||||
from parver import Version
|
||||
|
||||
from pipenv.__version__ import __version__
|
||||
@@ -14,7 +13,6 @@ from pipenv.vendor.vistir.contextmanagers import temp_environ
|
||||
|
||||
from .vendoring import _get_git_root, drop_dir
|
||||
|
||||
|
||||
VERSION_FILE = "pipenv/__version__.py"
|
||||
ROOT = pathlib.Path(".").parent.parent.absolute()
|
||||
PACKAGE_NAME = "pipenv"
|
||||
@@ -49,8 +47,7 @@ def get_build_dir(ctx):
|
||||
|
||||
|
||||
def _render_log():
|
||||
"""Totally tap into Towncrier internals to get an in-memory result.
|
||||
"""
|
||||
"""Totally tap into Towncrier internals to get an in-memory result."""
|
||||
rendered = subprocess.check_output(["towncrier", "--draft"]).decode("utf-8")
|
||||
return rendered
|
||||
|
||||
@@ -66,7 +63,9 @@ release_help = {
|
||||
|
||||
|
||||
@invoke.task(help=release_help)
|
||||
def release(ctx, manual=False, local=False, dry_run=False, pre=False, tag=None, month_offset="0"):
|
||||
def release(
|
||||
ctx, manual=False, local=False, dry_run=False, pre=False, tag=None, month_offset="0"
|
||||
):
|
||||
trunc_month = False
|
||||
if pre:
|
||||
trunc_month = True
|
||||
@@ -77,7 +76,7 @@ def release(ctx, manual=False, local=False, dry_run=False, pre=False, tag=None,
|
||||
pre=pre,
|
||||
tag=tag,
|
||||
month_offset=month_offset,
|
||||
trunc_month=trunc_month
|
||||
trunc_month=trunc_month,
|
||||
)
|
||||
tag_content = _render_log()
|
||||
if dry_run:
|
||||
@@ -93,9 +92,7 @@ def release(ctx, manual=False, local=False, dry_run=False, pre=False, tag=None,
|
||||
ctx.run(f"git add {get_version_file(ctx).as_posix()}")
|
||||
else:
|
||||
ctx.run("towncrier")
|
||||
ctx.run(
|
||||
f"git add CHANGELOG.rst news/ {get_version_file(ctx).as_posix()}"
|
||||
)
|
||||
ctx.run(f"git add CHANGELOG.rst news/ {get_version_file(ctx).as_posix()}")
|
||||
log("removing changelog draft if present")
|
||||
draft_changelog = pathlib.Path("CHANGELOG.draft.rst")
|
||||
if draft_changelog.exists():
|
||||
@@ -150,11 +147,9 @@ def build_dists(ctx):
|
||||
log("Building sdist using %s ...." % executable)
|
||||
os.environ["PIPENV_PYTHON"] = py_version
|
||||
ctx.run("pipenv install --dev", env=env)
|
||||
ctx.run(
|
||||
"pipenv run pip install -e . --upgrade --upgrade-strategy=eager", env=env
|
||||
)
|
||||
ctx.run("pipenv run pip install -e . --upgrade --upgrade-strategy=eager", env=env)
|
||||
log("Building wheel using python %s ...." % py_version)
|
||||
ctx.run(f"pipenv run python setup.py sdist bdist_wheel", env=env)
|
||||
ctx.run("pipenv run python setup.py sdist bdist_wheel", env=env)
|
||||
|
||||
|
||||
@invoke.task(build_dists)
|
||||
@@ -266,9 +261,11 @@ def date_offset(dt, month_offset=0, day_offset=0, truncate=False):
|
||||
"month": dt.month + month_offset,
|
||||
"year": dt.year + year_offset,
|
||||
}
|
||||
log("Getting updated date from date: {} using month offset: {} and year offset {}".format(
|
||||
log(
|
||||
"Getting updated date from date: {} using month offset: {} and year offset {}".format(
|
||||
dt, new_month, replace_args["year"]
|
||||
))
|
||||
)
|
||||
)
|
||||
if day_offset:
|
||||
dt = dt + datetime.timedelta(days=day_offset)
|
||||
log(f"updated date using day offset: {day_offset} => {dt}")
|
||||
@@ -279,7 +276,16 @@ def date_offset(dt, month_offset=0, day_offset=0, truncate=False):
|
||||
|
||||
|
||||
@invoke.task
|
||||
def bump_version(ctx, dry_run=False, dev=False, pre=False, tag=None, commit=False, month_offset="0", trunc_month=False):
|
||||
def bump_version(
|
||||
ctx,
|
||||
dry_run=False,
|
||||
dev=False,
|
||||
pre=False,
|
||||
tag=None,
|
||||
commit=False,
|
||||
month_offset="0",
|
||||
trunc_month=False,
|
||||
):
|
||||
current_version = Version.parse(__version__)
|
||||
current_date = datetime.date(*current_version.release)
|
||||
today = datetime.date.today()
|
||||
@@ -295,10 +301,7 @@ def bump_version(ctx, dry_run=False, dev=False, pre=False, tag=None, commit=Fals
|
||||
):
|
||||
day_offset = 1
|
||||
target_day = date_offset(
|
||||
today,
|
||||
month_offset=month_offset,
|
||||
day_offset=day_offset,
|
||||
truncate=trunc_month
|
||||
today, month_offset=month_offset, day_offset=day_offset, truncate=trunc_month
|
||||
)
|
||||
log(f"target_day: {target_day}")
|
||||
target_timetuple = target_day.timetuple()[:3]
|
||||
|
||||
+26
-31
@@ -3,26 +3,20 @@
|
||||
""""Vendoring script, python 3.5 needed"""
|
||||
|
||||
import itertools
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
|
||||
# from tempfile import TemporaryDirectory
|
||||
import tarfile
|
||||
import zipfile
|
||||
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
import bs4
|
||||
import invoke
|
||||
import requests
|
||||
|
||||
from urllib3.util import parse_url as urllib3_parse
|
||||
|
||||
from tempfile import TemporaryDirectory
|
||||
from pipenv.vendor.vistir.contextmanagers import open_file
|
||||
import pipenv.vendor.parse as parse
|
||||
|
||||
from pipenv.vendor.vistir.contextmanagers import open_file
|
||||
|
||||
TASK_NAME = "update"
|
||||
|
||||
@@ -190,10 +184,16 @@ def rewrite_file_imports(item, vendored_libs):
|
||||
|
||||
for lib, to_lib in vendored_libs.items():
|
||||
text = re.sub(
|
||||
r"^(?m)(\s*)import %s((?:\.\S*)?\s+as)" % lib, r"\1import %s\2" % to_lib, text,
|
||||
r"^(?m)(\s*)import %s((?:\.\S*)?\s+as)" % lib,
|
||||
r"\1import %s\2" % to_lib,
|
||||
text,
|
||||
)
|
||||
text = re.sub(r"^(?m)(\s*)from %s([\s\.]+)" % lib, r"\1from %s\2" % to_lib, text)
|
||||
text = re.sub(r"^(?m)(\s*)import %s(\s*[,\n#])" % lib, r"\1import %s as %s\2" % (to_lib, lib), text)
|
||||
text = re.sub(
|
||||
r"^(?m)(\s*)import %s(\s*[,\n#])" % lib,
|
||||
r"\1import %s as %s\2" % (to_lib, lib),
|
||||
text,
|
||||
)
|
||||
for pattern, sub in GLOBAL_REPLACEMENT:
|
||||
text = re.sub(pattern, sub, text)
|
||||
item.write_text(text, encoding="utf-8")
|
||||
@@ -209,7 +209,7 @@ def _recursive_write_to_zip(zf, path, root=None):
|
||||
return
|
||||
if root is None:
|
||||
if not path.is_dir():
|
||||
raise ValueError('root is required for non-directory path')
|
||||
raise ValueError("root is required for non-directory path")
|
||||
root = path
|
||||
if not path.is_dir():
|
||||
zf.write(str(path), str(path.relative_to(root)))
|
||||
@@ -251,7 +251,7 @@ def write_backport_imports(ctx, vendor_dir):
|
||||
def _ensure_package_in_requirements(ctx, requirements_file, package):
|
||||
requirement = None
|
||||
log("using requirements file: %s" % requirements_file)
|
||||
req_file_lines = [l for l in requirements_file.read_text().splitlines()]
|
||||
req_file_lines = [line for line in requirements_file.read_text().splitlines()]
|
||||
if package:
|
||||
match = [r for r in req_file_lines if r.strip().lower().startswith(package)]
|
||||
matched_req = None
|
||||
@@ -274,9 +274,11 @@ def _ensure_package_in_requirements(ctx, requirements_file, package):
|
||||
|
||||
def install_pyyaml(ctx, vendor_dir):
|
||||
with TemporaryDirectory(prefix="pipenv-", suffix="-yaml") as download_dir:
|
||||
pip_command = "pip download --no-binary=:all: --no-clean --no-deps -d {} pyyaml".format(
|
||||
pip_command = (
|
||||
"pip download --no-binary=:all: --no-clean --no-deps -d {} pyyaml".format(
|
||||
download_dir
|
||||
)
|
||||
)
|
||||
log(f"downloading deps via pip: {pip_command}")
|
||||
ctx.run(pip_command)
|
||||
downloaded = next(Path(download_dir).glob("*.tar.gz"))
|
||||
@@ -291,7 +293,9 @@ def install_pyyaml(ctx, vendor_dir):
|
||||
if yaml_dir.exists():
|
||||
drop_dir(yaml_dir)
|
||||
path_dict["current_path"].rename(path_dict["destination"])
|
||||
path_dict["destination"].joinpath("LICENSE").write_text(extracted.joinpath("LICENSE").read_text())
|
||||
path_dict["destination"].joinpath("LICENSE").write_text(
|
||||
extracted.joinpath("LICENSE").read_text()
|
||||
)
|
||||
|
||||
|
||||
def install(ctx, vendor_dir, package=None):
|
||||
@@ -305,7 +309,8 @@ def install(ctx, vendor_dir, package=None):
|
||||
# the chain.
|
||||
ctx.run(
|
||||
"pip install -t {} --no-compile --no-deps --upgrade {}".format(
|
||||
vendor_dir.as_posix(), requirement,
|
||||
vendor_dir.as_posix(),
|
||||
requirement,
|
||||
)
|
||||
)
|
||||
# read licenses from distinfo files if possible
|
||||
@@ -319,22 +324,16 @@ def install(ctx, vendor_dir, package=None):
|
||||
license_file.read_text()
|
||||
)
|
||||
elif vendor_dir.joinpath(f"{pkg}.py").exists():
|
||||
vendor_dir.joinpath(f"{pkg}.LICENSE").write_text(
|
||||
license_file.read_text()
|
||||
)
|
||||
vendor_dir.joinpath(f"{pkg}.LICENSE").write_text(license_file.read_text())
|
||||
else:
|
||||
pkg = pkg.replace("-", "?").replace("_", "?")
|
||||
matched_path = next(
|
||||
iter(pth for pth in vendor_dir.glob(f"{pkg}*")), None
|
||||
)
|
||||
matched_path = next(iter(pth for pth in vendor_dir.glob(f"{pkg}*")), None)
|
||||
if matched_path is not None:
|
||||
if matched_path.is_dir():
|
||||
target = vendor_dir.joinpath(matched_path).joinpath("LICENSE")
|
||||
else:
|
||||
target = vendor_dir.joinpath(f"{matched_path}.LICENSE")
|
||||
target.write_text(
|
||||
license_file.read_text()
|
||||
)
|
||||
target.write_text(license_file.read_text())
|
||||
|
||||
|
||||
def post_install_cleanup(ctx, vendor_dir):
|
||||
@@ -460,7 +459,7 @@ def packages_missing_licenses(
|
||||
".".join(lic)
|
||||
for lic in itertools.product(("LICENSE", "LICENSE-MIT"), LICENSE_EXTS)
|
||||
]
|
||||
for i, req in enumerate(requirements):
|
||||
for _, req in enumerate(requirements):
|
||||
if req.startswith("git+"):
|
||||
pkg = req.strip().split("#egg=")[1]
|
||||
else:
|
||||
@@ -549,9 +548,7 @@ def download_licenses(
|
||||
if "." in backend:
|
||||
backend, _, _ = backend.partition(".")
|
||||
ctx.run(f"pip install {backend}")
|
||||
ctx.run(
|
||||
f"{cmd} --no-build-isolation -d {tmp_dir.as_posix()} {req}"
|
||||
)
|
||||
ctx.run(f"{cmd} --no-build-isolation -d {tmp_dir.as_posix()} {req}")
|
||||
for sdist in tmp_dir.iterdir():
|
||||
extract_license(vendor_dir, sdist)
|
||||
drop_dir(tmp_dir)
|
||||
@@ -720,9 +717,7 @@ def unpin_and_copy_requirements(ctx, requirement_file, name="requirements.txt"):
|
||||
ctx.run("pipenv --rm", env=env, hide=True)
|
||||
result = list(sorted(line.strip() for line in result.splitlines()[1:]))
|
||||
new_requirements = requirement_file.parent.joinpath(name)
|
||||
requirement_file.rename(
|
||||
requirement_file.parent.joinpath(f"{name}.bak")
|
||||
)
|
||||
requirement_file.rename(requirement_file.parent.joinpath(f"{name}.bak"))
|
||||
new_requirements.write_text("\n".join(result))
|
||||
return result
|
||||
|
||||
|
||||
Reference in New Issue
Block a user