mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
Merge branch 'master' into 1910-try_harder_to_cleanup_virtualenv
This commit is contained in:
+6
-1
@@ -9,6 +9,7 @@ env:
|
||||
- TEST_SUITE='dotvenv or check or unused or requirements'
|
||||
- TEST_SUITE='complex'
|
||||
- TEST_SUITE='markers or run or project or utils'
|
||||
- TEST_SUITE='not (dotvenv or check or unused or requirements or complex or markers or run or project or utils or install)'
|
||||
|
||||
# command to install dependencies
|
||||
install:
|
||||
@@ -18,6 +19,7 @@ install:
|
||||
|
||||
# command to run the dependencies
|
||||
script:
|
||||
- 'if [[ -n "$RUN_INTEGRATION_TESTS" ]]; then rm -fr ~/.cache/pip; fi'
|
||||
- "pipenv run bash ./run-tests.sh"
|
||||
|
||||
jobs:
|
||||
@@ -25,7 +27,10 @@ jobs:
|
||||
- stage: integration
|
||||
env: TEST_SUITE='cli'
|
||||
- stage: takes-forever
|
||||
env: TEST_SUITE='install'
|
||||
env:
|
||||
- TEST_SUITE='install'
|
||||
- PYTEST_ADDOPTS='--cache-clear'
|
||||
- RUN_INTEGRATION_TESTS=1
|
||||
|
||||
stages:
|
||||
- integration
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
[dev-packages]
|
||||
|
||||
pipenv = {path = ".", editable = true}
|
||||
"flake8" = ">=3.3.0,<4"
|
||||
pytest = "*"
|
||||
@@ -11,16 +10,14 @@ pytest-xdist = "*"
|
||||
click = "*"
|
||||
pytest-pypy = {path = "./tests/pytest-pypi", editable = true}
|
||||
pytest-tap = "*"
|
||||
stdeb = {version="*", sys_platform="== 'linux'"}
|
||||
flaky = "*"
|
||||
stdeb = {version="*", markers="sys_platform == 'linux'"}
|
||||
white = {version="*", markers="python_version >= '3.6'"}
|
||||
|
||||
[packages]
|
||||
|
||||
|
||||
[scripts]
|
||||
|
||||
tests = "bash ./run-tests.sh"
|
||||
|
||||
[pipenv]
|
||||
|
||||
allow_prereleases = true
|
||||
allow_prereleases = true
|
||||
|
||||
Generated
+126
-10
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "8acf60476c4efca4f1be83dc747f18d4a663c3479e664e9e6865469f7ab9b958"
|
||||
"sha256": "5941b36256503b9729e927f3249a366748da5c353b59c1e32ca7fd919b31a4d6"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
@@ -29,6 +29,13 @@
|
||||
],
|
||||
"version": "==1.4"
|
||||
},
|
||||
"asn1crypto": {
|
||||
"hashes": [
|
||||
"sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87",
|
||||
"sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49"
|
||||
],
|
||||
"version": "==0.24.0"
|
||||
},
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
"sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9",
|
||||
@@ -50,6 +57,39 @@
|
||||
],
|
||||
"version": "==2018.1.18"
|
||||
},
|
||||
"cffi": {
|
||||
"hashes": [
|
||||
"sha256:151b7eefd035c56b2b2e1eb9963c90c6302dc15fbd8c1c0a83a163ff2c7d7743",
|
||||
"sha256:1553d1e99f035ace1c0544050622b7bc963374a00c467edafac50ad7bd276aef",
|
||||
"sha256:1b0493c091a1898f1136e3f4f991a784437fac3673780ff9de3bcf46c80b6b50",
|
||||
"sha256:2ba8a45822b7aee805ab49abfe7eec16b90587f7f26df20c71dd89e45a97076f",
|
||||
"sha256:3c85641778460581c42924384f5e68076d724ceac0f267d66c757f7535069c93",
|
||||
"sha256:3eb6434197633b7748cea30bf0ba9f66727cdce45117a712b29a443943733257",
|
||||
"sha256:4c91af6e967c2015729d3e69c2e51d92f9898c330d6a851bf8f121236f3defd3",
|
||||
"sha256:770f3782b31f50b68627e22f91cb182c48c47c02eb405fd689472aa7b7aa16dc",
|
||||
"sha256:79f9b6f7c46ae1f8ded75f68cf8ad50e5729ed4d590c74840471fc2823457d04",
|
||||
"sha256:7a33145e04d44ce95bcd71e522b478d282ad0eafaf34fe1ec5bbd73e662f22b6",
|
||||
"sha256:857959354ae3a6fa3da6651b966d13b0a8bed6bbc87a0de7b38a549db1d2a359",
|
||||
"sha256:87f37fe5130574ff76c17cab61e7d2538a16f843bb7bca8ebbc4b12de3078596",
|
||||
"sha256:95d5251e4b5ca00061f9d9f3d6fe537247e145a8524ae9fd30a2f8fbce993b5b",
|
||||
"sha256:9d1d3e63a4afdc29bd76ce6aa9d58c771cd1599fbba8cf5057e7860b203710dd",
|
||||
"sha256:a36c5c154f9d42ec176e6e620cb0dd275744aa1d804786a71ac37dc3661a5e95",
|
||||
"sha256:ae5e35a2c189d397b91034642cb0eab0e346f776ec2eb44a49a459e6615d6e2e",
|
||||
"sha256:b0f7d4a3df8f06cf49f9f121bead236e328074de6449866515cea4907bbc63d6",
|
||||
"sha256:b75110fb114fa366b29a027d0c9be3709579602ae111ff61674d28c93606acca",
|
||||
"sha256:ba5e697569f84b13640c9e193170e89c13c6244c24400fc57e88724ef610cd31",
|
||||
"sha256:be2a9b390f77fd7676d80bc3cdc4f8edb940d8c198ed2d8c0be1319018c778e1",
|
||||
"sha256:d5d8555d9bfc3f02385c1c37e9f998e2011f0db4f90e250e5bc0c0a85a813085",
|
||||
"sha256:e55e22ac0a30023426564b1059b035973ec82186ddddbac867078435801c7801",
|
||||
"sha256:e90f17980e6ab0f3c2f3730e56d1fe9bcba1891eeea58966e89d352492cc74f4",
|
||||
"sha256:ecbb7b01409e9b782df5ded849c178a0aa7c906cf8c5a67368047daab282b184",
|
||||
"sha256:ed01918d545a38998bfa5902c7c00e0fee90e957ce036a4000a88e3fe2264917",
|
||||
"sha256:edabd457cd23a02965166026fd9bfd196f4324fe6032e866d0f3bd0301cd486f",
|
||||
"sha256:fdf1c1dc5bafc32bc5d08b054f94d659422b05aba244d6be4ddc1c72d9aa70fb"
|
||||
],
|
||||
"markers": "platform_python_implementation != 'pypy'",
|
||||
"version": "==1.11.5"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||
@@ -73,6 +113,35 @@
|
||||
"markers": "sys_platform == 'win32'",
|
||||
"version": "==0.3.9"
|
||||
},
|
||||
"configparser": {
|
||||
"hashes": [
|
||||
"sha256:5308b47021bc2340965c371f0f058cc6971a04502638d4244225c49d80db273a"
|
||||
],
|
||||
"markers": "python_version < '3.2'",
|
||||
"version": "==3.5.0"
|
||||
},
|
||||
"cryptography": {
|
||||
"hashes": [
|
||||
"sha256:3f3b65d5a16e6b52fba63dc860b62ca9832f51f1a2ae5083c78b6840275f12dd",
|
||||
"sha256:551a3abfe0c8c6833df4192a63371aa2ff43afd8f570ed345d31f251d78e7e04",
|
||||
"sha256:5cb990056b7cadcca26813311187ad751ea644712022a3976443691168781b6f",
|
||||
"sha256:60bda7f12ecb828358be53095fc9c6edda7de8f1ef571f96c00b2363643fa3cd",
|
||||
"sha256:6fef51ec447fe9f8351894024e94736862900d3a9aa2961528e602eb65c92bdb",
|
||||
"sha256:77d0ad229d47a6e0272d00f6bf8ac06ce14715a9fd02c9a97f5a2869aab3ccb2",
|
||||
"sha256:808fe471b1a6b777f026f7dc7bd9a4959da4bfab64972f2bbe91e22527c1c037",
|
||||
"sha256:9b62fb4d18529c84b961efd9187fecbb48e89aa1a0f9f4161c61b7fc42a101bd",
|
||||
"sha256:9e5bed45ec6b4f828866ac6a6bedf08388ffcfa68abe9e94b34bb40977aba531",
|
||||
"sha256:9fc295bf69130a342e7a19a39d7bbeb15c0bcaabc7382ec33ef3b2b7d18d2f63",
|
||||
"sha256:abd070b5849ed64e6d349199bef955ee0ad99aefbad792f0c587f8effa681a5e",
|
||||
"sha256:ba6a774749b6e510cffc2fb98535f717e0e5fd91c7c99a61d223293df79ab351",
|
||||
"sha256:c332118647f084c983c6a3e1dba0f3bcb051f69d12baccac68db8d62d177eb8a",
|
||||
"sha256:d6f46e862ee36df81e6342c2177ba84e70f722d9dc9c6c394f9f1f434c4a5563",
|
||||
"sha256:db6013746f73bf8edd9c3d1d3f94db635b9422f503db3fc5ef105233d4c011ab",
|
||||
"sha256:f57008eaff597c69cf692c3518f6d4800f0309253bb138b526a37fe9ef0c7471",
|
||||
"sha256:f6c821ac253c19f2ad4c8691633ae1d1a17f120d5b01ea1d256d7b602bc59887"
|
||||
],
|
||||
"version": "==2.2.2"
|
||||
},
|
||||
"docutils": {
|
||||
"hashes": [
|
||||
"sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
|
||||
@@ -81,6 +150,16 @@
|
||||
],
|
||||
"version": "==0.14"
|
||||
},
|
||||
"enum34": {
|
||||
"hashes": [
|
||||
"sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850",
|
||||
"sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a",
|
||||
"sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79",
|
||||
"sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1"
|
||||
],
|
||||
"markers": "python_version < '3'",
|
||||
"version": "==1.1.6"
|
||||
},
|
||||
"execnet": {
|
||||
"hashes": [
|
||||
"sha256:a7a84d5fa07a089186a329528f127c9d73b9de57f1a1131b82bb5320ee651f6a",
|
||||
@@ -96,6 +175,14 @@
|
||||
"index": "pypi",
|
||||
"version": "==3.5.0"
|
||||
},
|
||||
"flaky": {
|
||||
"hashes": [
|
||||
"sha256:4ad7880aef8c35a34ddb394d4fa33047765bca1e3d67d182bf6eba9c8eabf3a2",
|
||||
"sha256:d0533f473a46b916e6db6e84e20b06d8a70656600a0c14e819b0760b63f70226"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.4.0"
|
||||
},
|
||||
"flask": {
|
||||
"hashes": [
|
||||
"sha256:0749df235e3ff61ac108f69ac178c9770caeaccad2509cb762ce1f65570a8856",
|
||||
@@ -103,6 +190,14 @@
|
||||
],
|
||||
"version": "==0.12.2"
|
||||
},
|
||||
"funcsigs": {
|
||||
"hashes": [
|
||||
"sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca",
|
||||
"sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"
|
||||
],
|
||||
"markers": "python_version < '3.0'",
|
||||
"version": "==1.0.2"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f",
|
||||
@@ -117,6 +212,13 @@
|
||||
],
|
||||
"version": "==1.0.0"
|
||||
},
|
||||
"ipaddress": {
|
||||
"hashes": [
|
||||
"sha256:200d8686011d470b5e4de207d803445deee427455cd0cb7c982b68cf82524f81"
|
||||
],
|
||||
"markers": "python_version < '3'",
|
||||
"version": "==1.0.19"
|
||||
},
|
||||
"itsdangerous": {
|
||||
"hashes": [
|
||||
"sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519"
|
||||
@@ -159,19 +261,20 @@
|
||||
],
|
||||
"version": "==4.1.0"
|
||||
},
|
||||
"pathlib": {
|
||||
"pathlib2": {
|
||||
"hashes": [
|
||||
"sha256:6940718dfc3eff4258203ad5021090933e5c04707d5ca8cc9e73c94a7894ea9f"
|
||||
"sha256:24e0b33e1333b55e73c9d1e9a8342417d519f7789a9d3b440f4acd00ea45157e",
|
||||
"sha256:deb3a960c1d55868dfbcac98432358b92ba89d95029cddd4040db1f27405055c"
|
||||
],
|
||||
"markers": "python_version < '3.4'",
|
||||
"version": "==1.0.1"
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"pbr": {
|
||||
"hashes": [
|
||||
"sha256:05f61c71aaefc02d8e37c0a3eeb9815ff526ea28b3b76324769e6158d7f95be1",
|
||||
"sha256:60c25b7dfd054ef9bb0ae327af949dd4676aa09ac3a9471cdc871d8a9213f9ac"
|
||||
"sha256:56b7a8ba7d64bf6135a9dfefb85a80d95924b3fde5ed6343a1a1d464a040dae3",
|
||||
"sha256:de75cf1d510542c746beeff66b52241eb12c8f95f2ef846ee50ed5d72392caa4"
|
||||
],
|
||||
"version": "==3.1.1"
|
||||
"version": "==4.0.1"
|
||||
},
|
||||
"pipenv": {
|
||||
"editable": true,
|
||||
@@ -204,6 +307,12 @@
|
||||
],
|
||||
"version": "==2.3.1"
|
||||
},
|
||||
"pycparser": {
|
||||
"hashes": [
|
||||
"sha256:99a8ca03e29851d96616ad0404b4aad7d9ee16f25c9f9708a11faf2810f7b226"
|
||||
],
|
||||
"version": "==2.18"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f",
|
||||
@@ -218,6 +327,13 @@
|
||||
],
|
||||
"version": "==2.2.0"
|
||||
},
|
||||
"pyopenssl": {
|
||||
"hashes": [
|
||||
"sha256:07a2de1a54de07448732a81e38a55df7da109b2f47f599f8bb35b0cbec69d4bd",
|
||||
"sha256:2c10cfba46a52c0b0950118981d61e72c1e5b1aac451ca1bc77de1a679456773"
|
||||
],
|
||||
"version": "==17.5.0"
|
||||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:6266f87ab64692112e5477eba395cfedda53b1933ccd29478e671e73b420c19c",
|
||||
@@ -328,10 +444,10 @@
|
||||
},
|
||||
"tqdm": {
|
||||
"hashes": [
|
||||
"sha256:05e991ecb0f874046ddcb374396a626afd046fb4d31f73633ea752b844458a7a",
|
||||
"sha256:2aea9f81fdf127048667e0ba22f5fc10ebc879fb838dc52dcf055242037ec1f7"
|
||||
"sha256:4f2eb1d14804caf7095500fe11da0e481a47af912e7b57c93f886ac3c40a49dd",
|
||||
"sha256:91ac47ec2ba6bb92b7ba37706f4dea37019ddd784b22fd279a4b12d93327191d"
|
||||
],
|
||||
"version": "==4.19.8"
|
||||
"version": "==4.20.0"
|
||||
},
|
||||
"twine": {
|
||||
"hashes": [
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
build: off
|
||||
version: 1.0.{build}
|
||||
|
||||
skip_branch_with_pr: true
|
||||
|
||||
init:
|
||||
|
||||
- git config --global core.sharedRepository true
|
||||
- git config --global core.longpaths true
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
environment:
|
||||
|
||||
PYPI_VENDOR_DIR: '.\tests\pypi\'
|
||||
GIT_ASK_YESNO: 'false'
|
||||
SHELL: 'windows'
|
||||
PYTHON_ARCH: '64'
|
||||
PYTHONIOENCODING: 'utf-8'
|
||||
|
||||
matrix:
|
||||
|
||||
- PYTHON: 'C:\Python27-x64'
|
||||
PYTHON_VERSION: '2.7.x'
|
||||
TEST_SUITE: 'cli'
|
||||
|
||||
- PYTHON: 'C:\Python27-x64'
|
||||
PYTHON_VERSION: '2.7.x'
|
||||
TEST_SUITE: 'dotvenv or check or unused or requirements'
|
||||
|
||||
- PYTHON: 'C:\Python27-x64'
|
||||
PYTHON_VERSION: '2.7.x'
|
||||
TEST_SUITE: 'complex'
|
||||
|
||||
- PYTHON: 'C:\Python27-x64'
|
||||
PYTHON_VERSION: '2.7.x'
|
||||
TEST_SUITE: 'markers or run or project or utils'
|
||||
|
||||
- PYTHON: 'C:\Python27-x64'
|
||||
PYTHON_VERSION: '2.7.x'
|
||||
TEST_SUITE: 'not (cli or dotvenv or check or unused or requirements or complex or markers or run or project or utils)'
|
||||
|
||||
- PYTHON: 'C:\Python27-x64'
|
||||
PYTHON_VERSION: '2.7.x'
|
||||
TEST_SUITE: 'install'
|
||||
PYTEST_ADDOPTS: '--cache-clear'
|
||||
RUN_INTEGRATION_TESTS: 'True'
|
||||
|
||||
- PYTHON: 'C:\Python36-x64'
|
||||
PYTHON_VERSION: '3.6.x'
|
||||
TEST_SUITE: 'cli'
|
||||
|
||||
- PYTHON: 'C:\Python36-x64'
|
||||
PYTHON_VERSION: '3.6.x'
|
||||
TEST_SUITE: 'dotvenv or check or unused or requirements'
|
||||
|
||||
- PYTHON: 'C:\Python36-x64'
|
||||
PYTHON_VERSION: '3.6.x'
|
||||
TEST_SUITE: 'complex'
|
||||
|
||||
- PYTHON: 'C:\Python36-x64'
|
||||
PYTHON_VERSION: '3.6.x'
|
||||
TEST_SUITE: 'markers or run or project or utils'
|
||||
|
||||
- PYTHON: 'C:\Python36-x64'
|
||||
PYTHON_VERSION: '3.6.x'
|
||||
TEST_SUITE: 'not (cli or dotvenv or check or unused or requirements or complex or markers or run or project or utils)'
|
||||
|
||||
- PYTHON: 'C:\Python36-x64'
|
||||
PYTHON_VERSION: '3.6.x'
|
||||
TEST_SUITE: 'install'
|
||||
PYTEST_ADDOPTS: '--cache-clear'
|
||||
RUN_INTEGRATION_TESTS: 'True'
|
||||
|
||||
install:
|
||||
- 'set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH%'
|
||||
- '%PYTHON%\python.exe -m pip install --upgrade pip'
|
||||
- '%PYTHON%\python.exe -m pip install -e .'
|
||||
- '%PYTHON%\python.exe -m pipenv run pip install -e .'
|
||||
- '%PYTHON%\python.exe -m pipenv install --dev'
|
||||
- '%PYTHON%\python.exe -m pipenv --venv'
|
||||
- '%PYTHON%\python.exe -m pipenv --py'
|
||||
- '%PYTHON%\python.exe -m pipenv run python --version'
|
||||
|
||||
cache:
|
||||
- '%LocalAppData%\pip\cache'
|
||||
|
||||
test_script:
|
||||
- 'if "%RUN_INTEGRATION_TESTS%" == "True" (rmdir /s /q %LocalAppData%\pip\cache)'
|
||||
- '%PYTHON%\python.exe -m pipenv run pytest -v -n auto -m "%TEST_SUITE%" tests'
|
||||
+14
-14
@@ -11,7 +11,7 @@ from click_didyoumean import DYMCommandCollection
|
||||
|
||||
from .__version__ import __version__
|
||||
|
||||
from .import environments
|
||||
from . import environments
|
||||
from .environments import *
|
||||
|
||||
# Enable shell completion.
|
||||
@@ -23,7 +23,7 @@ class PipenvGroup(click.Group):
|
||||
"""Custom Group class provides formatted main help"""
|
||||
|
||||
def get_help_option(self, ctx):
|
||||
from .import core
|
||||
from . import core
|
||||
|
||||
"""Override for showing formatted main help via --help and -h options"""
|
||||
help_options = self.get_help_option_names(ctx)
|
||||
@@ -148,7 +148,7 @@ def cli(
|
||||
)
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
from .import core
|
||||
from . import core
|
||||
if man:
|
||||
if core.system_which('man'):
|
||||
path = os.sep.join([os.path.dirname(__file__), 'pipenv.1'])
|
||||
@@ -344,7 +344,7 @@ def install(
|
||||
keep_outdated=False,
|
||||
selective_upgrade=False,
|
||||
):
|
||||
from .import core
|
||||
from . import core
|
||||
|
||||
core.do_install(
|
||||
package_name=package_name,
|
||||
@@ -426,7 +426,7 @@ def uninstall(
|
||||
verbose=False,
|
||||
keep_outdated=False,
|
||||
):
|
||||
from .import core
|
||||
from . import core
|
||||
|
||||
core.do_uninstall(
|
||||
package_name=package_name,
|
||||
@@ -499,7 +499,7 @@ def lock(
|
||||
pre=False,
|
||||
keep_outdated=False,
|
||||
):
|
||||
from .import core
|
||||
from . import core
|
||||
|
||||
# Ensure that virtualenv is available.
|
||||
core.ensure_project(three=three, python=python)
|
||||
@@ -542,7 +542,7 @@ def lock(
|
||||
def shell(
|
||||
three=None, python=False, fancy=False, shell_args=None, anyway=False
|
||||
):
|
||||
from .import core
|
||||
from . import core
|
||||
|
||||
# Prevent user from activating nested environments.
|
||||
if 'PIPENV_ACTIVE' in os.environ:
|
||||
@@ -594,7 +594,7 @@ def shell(
|
||||
help="Specify which version of Python virtualenv should use.",
|
||||
)
|
||||
def run(command, args, three=None, python=False):
|
||||
from .import core
|
||||
from . import core
|
||||
|
||||
core.do_run(command=command, args=args, three=three, python=python)
|
||||
|
||||
@@ -633,7 +633,7 @@ def check(
|
||||
style=False,
|
||||
args=None,
|
||||
):
|
||||
from .import core
|
||||
from . import core
|
||||
|
||||
core.do_check(
|
||||
three=three, python=python, system=system, unused=unused, args=args
|
||||
@@ -719,7 +719,7 @@ def update(
|
||||
outdated=False,
|
||||
more_packages=None,
|
||||
):
|
||||
from .import core
|
||||
from . import core
|
||||
|
||||
core.ensure_project(three=three, python=python, warn=True)
|
||||
if not outdated:
|
||||
@@ -797,7 +797,7 @@ def update(
|
||||
'--reverse', is_flag=True, default=False, help="Reversed dependency graph."
|
||||
)
|
||||
def graph(bare=False, json=False, reverse=False):
|
||||
from .import core
|
||||
from . import core
|
||||
|
||||
core.do_graph(bare=bare, json=json, reverse=reverse)
|
||||
|
||||
@@ -817,7 +817,7 @@ def graph(bare=False, json=False, reverse=False):
|
||||
)
|
||||
@click.argument('module', nargs=1)
|
||||
def run_open(module, three=None, python=None):
|
||||
from .import core
|
||||
from . import core
|
||||
|
||||
# Ensure that virtualenv is available.
|
||||
core.ensure_project(three=three, python=python, validate=False)
|
||||
@@ -895,7 +895,7 @@ def sync(
|
||||
package_name=None,
|
||||
sequential=False,
|
||||
):
|
||||
from .import core
|
||||
from . import core
|
||||
|
||||
core.do_sync(
|
||||
ctx=ctx,
|
||||
@@ -952,7 +952,7 @@ def clean(
|
||||
user=False,
|
||||
verbose=False,
|
||||
):
|
||||
from .import core
|
||||
from . import core
|
||||
|
||||
core.do_clean(
|
||||
ctx=ctx, three=three, python=python, dry_run=dry_run, verbose=verbose
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import re
|
||||
import shlex
|
||||
|
||||
import six
|
||||
|
||||
|
||||
class ScriptEmptyError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
class Script(object):
|
||||
"""Parse a script line (in Pipfile's [scripts] section).
|
||||
|
||||
This always works in POSIX mode, even on Windows.
|
||||
"""
|
||||
def __init__(self, command, args=None):
|
||||
self._parts = [command]
|
||||
if args:
|
||||
self._parts.extend(args)
|
||||
|
||||
@classmethod
|
||||
def parse(cls, value):
|
||||
if isinstance(value, six.string_types):
|
||||
value = shlex.split(value)
|
||||
if not value:
|
||||
raise ScriptEmptyError(value)
|
||||
return cls(value[0], value[1:])
|
||||
|
||||
def __repr__(self):
|
||||
return 'Script({0!r})'.format(self._parts)
|
||||
|
||||
@property
|
||||
def command(self):
|
||||
return self._parts[0]
|
||||
|
||||
@property
|
||||
def args(self):
|
||||
return self._parts[1:]
|
||||
|
||||
def extend(self, extra_args):
|
||||
self._parts.extend(extra_args)
|
||||
|
||||
def cmdify(self):
|
||||
"""Encode into a cmd-executable string.
|
||||
|
||||
This re-implements CreateProcess's quoting logic to turn a list of
|
||||
arguments into one single string for the shell to interpret.
|
||||
|
||||
* All double quotes are escaped with a backslash.
|
||||
* Existing backslashes before a quote are doubled, so they are all
|
||||
escaped properly.
|
||||
* Backslashes elsewhere are left as-is; cmd will interpret them
|
||||
literally.
|
||||
|
||||
The result is then quoted into a pair of double quotes to be grouped.
|
||||
|
||||
The intended use of this function is to pre-process an argument list
|
||||
before passing it into ``subprocess.Popen(..., shell=True)``.
|
||||
|
||||
See also: https://docs.python.org/3/library/subprocess.html#converting-argument-sequence
|
||||
"""
|
||||
return ' '.join(
|
||||
'"{0}"'.format(re.sub(r'(\\*)"', r'\1\1\\"', arg))
|
||||
for arg in self._parts
|
||||
)
|
||||
+18
-34
@@ -4,7 +4,6 @@ import logging
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import shlex
|
||||
import signal
|
||||
import time
|
||||
import tempfile
|
||||
@@ -25,6 +24,7 @@ from blindspin import spinner
|
||||
from requests.packages import urllib3
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
|
||||
from .cmdparse import ScriptEmptyError
|
||||
from .project import Project
|
||||
from .utils import (
|
||||
convert_deps_from_pip,
|
||||
@@ -2203,46 +2203,22 @@ def inline_activate_virtualenv():
|
||||
)
|
||||
|
||||
|
||||
def do_run_nt(command, args):
|
||||
"""Run command by appending space-joined args to it!"""
|
||||
def do_run_nt(script):
|
||||
import subprocess
|
||||
command = project.scripts.get(command, command)
|
||||
|
||||
# if you've passed something with crazy quoting...
|
||||
# ...just don't. (or put it in a script!)
|
||||
p = subprocess.Popen(
|
||||
' '.join([command] + list(args)), shell=True, universal_newlines=True
|
||||
)
|
||||
p = subprocess.Popen(script.cmdify(), shell=True, universal_newlines=True)
|
||||
p.communicate()
|
||||
sys.exit(p.returncode)
|
||||
|
||||
|
||||
def _get_command_posix(project, command, args):
|
||||
"""Fully bake command into executable and args, based upon project"""
|
||||
# Script was found…
|
||||
if command in project.scripts:
|
||||
command = project.scripts[command]
|
||||
parsed_command = shlex.split(command)
|
||||
executable = parsed_command[0]
|
||||
# prepend arguments
|
||||
args = list(parsed_command[1:]) + list(args)
|
||||
return executable, args
|
||||
|
||||
|
||||
def do_run_posix(command, args):
|
||||
"""Attempt to run command either pulling from project or interpreting as executable.
|
||||
|
||||
Args are appended to the command in [scripts] section of project if found.
|
||||
"""
|
||||
executable, args = _get_command_posix(project, command, args)
|
||||
command_path = system_which(executable)
|
||||
def do_run_posix(script, command):
|
||||
command_path = system_which(script.command)
|
||||
if not command_path:
|
||||
if command in project.scripts:
|
||||
if project.has_script(command):
|
||||
click.echo(
|
||||
'{0}: the command {1} (from {2}) could not be found within {3}.'
|
||||
''.format(
|
||||
crayons.red('Error', bold=True),
|
||||
crayons.red(executable),
|
||||
crayons.red(script.command),
|
||||
crayons.normal(command, bold=True),
|
||||
crayons.normal('PATH', bold=True),
|
||||
),
|
||||
@@ -2260,19 +2236,27 @@ def do_run_posix(command, args):
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
os.execl(command_path, command_path, *args)
|
||||
os.execl(command_path, command_path, *script.args)
|
||||
|
||||
|
||||
def do_run(command, args, three=None, python=False):
|
||||
"""Attempt to run command either pulling from project or interpreting as executable.
|
||||
|
||||
Args are appended to the command in [scripts] section of project if found.
|
||||
"""
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python, validate=False)
|
||||
load_dot_env()
|
||||
# Activate virtualenv under the current interpreter's environment
|
||||
inline_activate_virtualenv()
|
||||
try:
|
||||
script = project.build_script(command, args)
|
||||
except ScriptEmptyError:
|
||||
click.echo("Can't run script {0!r}—it's empty?", err=True)
|
||||
if os.name == 'nt':
|
||||
do_run_nt(command, args)
|
||||
do_run_nt(script)
|
||||
else:
|
||||
do_run_posix(command, args)
|
||||
do_run_posix(script, command=command)
|
||||
|
||||
|
||||
def do_check(three=None, python=False, system=False, unused=False, args=None):
|
||||
|
||||
@@ -6,7 +6,10 @@ from contextlib import contextmanager
|
||||
from subprocess import check_call, Popen, PIPE
|
||||
from collections import namedtuple
|
||||
from functools import partial, wraps
|
||||
from pathlib import Path
|
||||
try:
|
||||
from pathlib import Path
|
||||
except ImportError:
|
||||
from pathlib2 import Path
|
||||
from tempfile import NamedTemporaryFile as _ntf
|
||||
try:
|
||||
from shutil import which
|
||||
|
||||
@@ -8,7 +8,10 @@ import random
|
||||
import textwrap
|
||||
from functools import partial
|
||||
from subprocess import CalledProcessError
|
||||
from pathlib import Path
|
||||
try:
|
||||
from pathlib import Path
|
||||
except ImportError:
|
||||
from pathlib2 import Path
|
||||
|
||||
try:
|
||||
from shutil import get_terminal_size
|
||||
|
||||
+15
-3
@@ -16,6 +16,7 @@ import pipfile.api
|
||||
import toml
|
||||
|
||||
from pip9 import ConfigOptionParser
|
||||
from .cmdparse import Script
|
||||
from .utils import (
|
||||
mkdir_p,
|
||||
convert_deps_from_pip,
|
||||
@@ -388,9 +389,20 @@ class Project(object):
|
||||
"""A dictionary of the settings added to the Pipfile."""
|
||||
return self.parsed_pipfile.get('pipenv', {})
|
||||
|
||||
@property
|
||||
def scripts(self):
|
||||
return dict(self.parsed_pipfile.get('scripts', {}))
|
||||
def has_script(self, name):
|
||||
try:
|
||||
return name in self.parsed_pipfile['scripts']
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
def build_script(self, name, extra_args=None):
|
||||
try:
|
||||
script = Script.parse(self.parsed_pipfile['scripts'][name])
|
||||
except KeyError:
|
||||
script = Script(name)
|
||||
if extra_args:
|
||||
script.extend(extra_args)
|
||||
return script
|
||||
|
||||
def update_settings(self, d):
|
||||
settings = self.settings
|
||||
|
||||
+14
-8
@@ -60,14 +60,13 @@ if six.PY2:
|
||||
specifiers = [k for k in lookup.keys()]
|
||||
# List of version control systems we support.
|
||||
VCS_LIST = ('git', 'svn', 'hg', 'bzr')
|
||||
SCHEME_LIST = ('http://', 'https://', 'ftp://', 'file://')
|
||||
SCHEME_LIST = ('http://', 'https://', 'ftp://', 'ftps://', 'file://')
|
||||
requests = requests.Session()
|
||||
|
||||
|
||||
def get_requirement(dep):
|
||||
from pip9.req.req_install import _strip_extras
|
||||
import requirements
|
||||
|
||||
"""Pre-clean requirement strings passed to the requirements parser.
|
||||
|
||||
Ensures that we can accept both local and relative paths, file and VCS URIs,
|
||||
@@ -359,7 +358,7 @@ def actually_resolve_reps(
|
||||
def venv_resolve_deps(
|
||||
deps, which, project, pre=False, verbose=False, clear=False
|
||||
):
|
||||
from .import resolver
|
||||
from . import resolver
|
||||
import json
|
||||
|
||||
resolver = escape_grouped_arguments(resolver.__file__.rstrip('co'))
|
||||
@@ -560,7 +559,7 @@ def convert_deps_from_pip(dep):
|
||||
# Extras: e.g. #egg=requests[security]
|
||||
if req.extras:
|
||||
dependency[req.name].update({'extras': req.extras})
|
||||
elif req.extras or req.specs:
|
||||
elif req.extras or req.specs or hasattr(req, 'markers'):
|
||||
specs = None
|
||||
# Comparison operators: e.g. Django>1.10
|
||||
if req.specs:
|
||||
@@ -572,6 +571,10 @@ def convert_deps_from_pip(dep):
|
||||
dependency[req.name] = extras
|
||||
if specs:
|
||||
dependency[req.name].update({'version': specs})
|
||||
if hasattr(req, 'markers'):
|
||||
if isinstance(dependency[req.name], six.string_types):
|
||||
dependency[req.name] = {'version': specs}
|
||||
dependency[req.name].update({'markers': req.markers})
|
||||
# Bare dependencies: e.g. requests
|
||||
else:
|
||||
dependency[dep] = '*'
|
||||
@@ -679,8 +682,7 @@ def convert_deps_to_pip(deps, project=None, r=True, include_index=False):
|
||||
dep = ''
|
||||
s = '{0}{1}{2}{3}{4} {5}'.format(
|
||||
dep, extra, version, specs, hash, index
|
||||
).strip(
|
||||
)
|
||||
).strip()
|
||||
dependencies.append(s)
|
||||
if not r:
|
||||
return dependencies
|
||||
@@ -754,7 +756,7 @@ def is_editable(pipfile_entry):
|
||||
|
||||
|
||||
def is_vcs(pipfile_entry):
|
||||
import requirements
|
||||
from pipenv.vendor import requirements
|
||||
|
||||
"""Determine if dictionary entry from Pipfile is for a vcs dependency."""
|
||||
if hasattr(pipfile_entry, 'keys'):
|
||||
@@ -1019,6 +1021,10 @@ def find_windows_executable(bin_path, exe_name):
|
||||
return find_executable(exe_name)
|
||||
|
||||
|
||||
def path_to_url(path):
|
||||
return Path(normalize_drive(os.path.abspath(path))).as_uri()
|
||||
|
||||
|
||||
def get_converted_relative_path(path, relative_to=os.curdir):
|
||||
"""Given a vague relative path, return the path relative to the given location"""
|
||||
return os.path.join('.', os.path.relpath(path, start=relative_to))
|
||||
@@ -1212,7 +1218,7 @@ class TemporaryDirectory(object):
|
||||
import uuid
|
||||
|
||||
name = uuid.uuid4().hex
|
||||
dir_name = os.path.sep.join([os.environ['RAM_DISK'].strip(), name])
|
||||
dir_name = os.path.join(os.environ['RAM_DISK'].strip(), name)
|
||||
os.mkdir(dir_name)
|
||||
self.name = dir_name
|
||||
else:
|
||||
|
||||
Vendored
+2
-1
@@ -2,4 +2,5 @@ from pkgutil import extend_path
|
||||
__path__ = extend_path(__path__, __name__)
|
||||
|
||||
from . import shutil_get_terminal_size
|
||||
from . import weakref
|
||||
from . import weakref
|
||||
from . import shlex
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
"""
|
||||
Partial backport of python 3's shlex module.
|
||||
|
||||
Include's only `shlex.quote()` for backwards compatible functionality.
|
||||
"""
|
||||
|
||||
__all__ = ['quote']
|
||||
|
||||
from .shlex import quote
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
__all__ = ['quote']
|
||||
|
||||
if sys.version_info >= (3, 1):
|
||||
_find_unsafe = re.compile(r'[^\w@%+=:,./-]', re.ASCII).search
|
||||
else:
|
||||
_find_unsafe = re.compile(r'[^\w@%+=:,./-]').search
|
||||
|
||||
|
||||
def quote(s):
|
||||
"""Return a shell-escaped version of the string *s*."""
|
||||
if not s:
|
||||
return "''"
|
||||
if _find_unsafe(s) is None:
|
||||
return s
|
||||
|
||||
# use single quotes, and put single quotes into double quotes
|
||||
# the string $'b is then quoted as '$'"'"'b'
|
||||
return "'" + s.replace("'", "'\"'\"'") + "'"
|
||||
Vendored
+105
-208
@@ -1,7 +1,3 @@
|
||||
# Copyright (c) 2014-2017 Matthias C. M. Troffaes
|
||||
# Copyright (c) 2012-2014 Antoine Pitrou and contributors
|
||||
# Distributed under the terms of the MIT License.
|
||||
|
||||
import ctypes
|
||||
import fnmatch
|
||||
import functools
|
||||
@@ -13,7 +9,8 @@ import re
|
||||
import six
|
||||
import sys
|
||||
from collections import Sequence
|
||||
from errno import EINVAL, ENOENT, ENOTDIR, EEXIST, EPERM, EACCES
|
||||
from contextlib import contextmanager
|
||||
from errno import EINVAL, ENOENT, ENOTDIR, EEXIST
|
||||
from operator import attrgetter
|
||||
from stat import (
|
||||
S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO)
|
||||
@@ -27,22 +24,23 @@ try:
|
||||
intern = intern
|
||||
except NameError:
|
||||
intern = sys.intern
|
||||
try:
|
||||
basestring = basestring
|
||||
except NameError:
|
||||
basestring = str
|
||||
|
||||
supports_symlinks = True
|
||||
if os.name == 'nt':
|
||||
try:
|
||||
import nt
|
||||
except ImportError:
|
||||
nt = None
|
||||
else:
|
||||
if sys.getwindowsversion()[:2] >= (6, 0) and sys.version_info >= (3, 2):
|
||||
from nt import _getfinalpathname
|
||||
else:
|
||||
supports_symlinks = False
|
||||
_getfinalpathname = None
|
||||
else:
|
||||
nt = None
|
||||
|
||||
try:
|
||||
from os import scandir as os_scandir
|
||||
except ImportError:
|
||||
from scandir import scandir as os_scandir
|
||||
|
||||
__all__ = [
|
||||
"PurePath", "PurePosixPath", "PureWindowsPath",
|
||||
@@ -61,15 +59,12 @@ def _py2_fsencode(parts):
|
||||
else part for part in parts]
|
||||
|
||||
|
||||
def _try_except_fileexistserror(try_func, except_func, else_func=None):
|
||||
def _try_except_fileexistserror(try_func, except_func):
|
||||
if sys.version_info >= (3, 3):
|
||||
try:
|
||||
try_func()
|
||||
except FileExistsError as exc:
|
||||
except_func(exc)
|
||||
else:
|
||||
if else_func is not None:
|
||||
else_func()
|
||||
else:
|
||||
try:
|
||||
try_func()
|
||||
@@ -78,45 +73,6 @@ def _try_except_fileexistserror(try_func, except_func, else_func=None):
|
||||
raise
|
||||
else:
|
||||
except_func(exc)
|
||||
else:
|
||||
if else_func is not None:
|
||||
else_func()
|
||||
|
||||
|
||||
def _try_except_filenotfounderror(try_func, except_func):
|
||||
if sys.version_info >= (3, 3):
|
||||
try:
|
||||
try_func()
|
||||
except FileNotFoundError as exc:
|
||||
except_func(exc)
|
||||
else:
|
||||
try:
|
||||
try_func()
|
||||
except EnvironmentError as exc:
|
||||
if exc.errno != ENOENT:
|
||||
raise
|
||||
else:
|
||||
except_func(exc)
|
||||
|
||||
|
||||
def _try_except_permissionerror_iter(try_iter, except_iter):
|
||||
if sys.version_info >= (3, 3):
|
||||
try:
|
||||
for x in try_iter():
|
||||
yield x
|
||||
except PermissionError as exc:
|
||||
for x in except_iter(exc):
|
||||
yield x
|
||||
else:
|
||||
try:
|
||||
for x in try_iter():
|
||||
yield x
|
||||
except EnvironmentError as exc:
|
||||
if exc.errno not in (EPERM, EACCES):
|
||||
raise
|
||||
else:
|
||||
for x in except_iter(exc):
|
||||
yield x
|
||||
|
||||
|
||||
def _win32_get_unique_path_id(path):
|
||||
@@ -264,7 +220,10 @@ class _WindowsFlavour(_Flavour):
|
||||
|
||||
is_supported = (os.name == 'nt')
|
||||
|
||||
drive_letters = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
|
||||
drive_letters = (
|
||||
set(chr(x) for x in range(ord('a'), ord('z') + 1)) |
|
||||
set(chr(x) for x in range(ord('A'), ord('Z') + 1))
|
||||
)
|
||||
ext_namespace_prefix = '\\\\?\\'
|
||||
|
||||
reserved_names = (
|
||||
@@ -324,28 +283,12 @@ class _WindowsFlavour(_Flavour):
|
||||
def casefold_parts(self, parts):
|
||||
return [p.lower() for p in parts]
|
||||
|
||||
def resolve(self, path, strict=False):
|
||||
def resolve(self, path):
|
||||
s = str(path)
|
||||
if not s:
|
||||
return os.getcwd()
|
||||
previous_s = None
|
||||
if _getfinalpathname is not None:
|
||||
if strict:
|
||||
return self._ext_to_normal(_getfinalpathname(s))
|
||||
else:
|
||||
# End of the path after the first one not found
|
||||
tail_parts = []
|
||||
while True:
|
||||
try:
|
||||
s = self._ext_to_normal(_getfinalpathname(s))
|
||||
except FileNotFoundError:
|
||||
previous_s = s
|
||||
s, tail = os.path.split(s)
|
||||
tail_parts.append(tail)
|
||||
if previous_s == s:
|
||||
return path
|
||||
else:
|
||||
return os.path.join(s, *reversed(tail_parts))
|
||||
return self._ext_to_normal(_getfinalpathname(s))
|
||||
# Means fallback on absolute
|
||||
return None
|
||||
|
||||
@@ -450,7 +393,7 @@ class _PosixFlavour(_Flavour):
|
||||
def casefold_parts(self, parts):
|
||||
return parts
|
||||
|
||||
def resolve(self, path, strict=False):
|
||||
def resolve(self, path):
|
||||
sep = self.sep
|
||||
accessor = path._accessor
|
||||
seen = {}
|
||||
@@ -481,10 +424,9 @@ class _PosixFlavour(_Flavour):
|
||||
try:
|
||||
target = accessor.readlink(newpath)
|
||||
except OSError as e:
|
||||
if e.errno != EINVAL and strict:
|
||||
if e.errno != EINVAL:
|
||||
raise
|
||||
# Not a symlink, or non-strict mode. We just leave the path
|
||||
# untouched.
|
||||
# Not a symlink
|
||||
path = newpath
|
||||
else:
|
||||
seen[newpath] = None # not resolved symlink
|
||||
@@ -521,7 +463,6 @@ class _PosixFlavour(_Flavour):
|
||||
raise RuntimeError("Can't determine home directory "
|
||||
"for %r" % username)
|
||||
|
||||
|
||||
_windows_flavour = _WindowsFlavour()
|
||||
_posix_flavour = _PosixFlavour()
|
||||
|
||||
@@ -554,8 +495,6 @@ class _NormalAccessor(_Accessor):
|
||||
|
||||
listdir = _wrap_strfunc(os.listdir)
|
||||
|
||||
scandir = _wrap_strfunc(os_scandir)
|
||||
|
||||
chmod = _wrap_strfunc(os.chmod)
|
||||
|
||||
if hasattr(os, "lchmod"):
|
||||
@@ -602,6 +541,27 @@ _normal_accessor = _NormalAccessor()
|
||||
# Globbing helpers
|
||||
#
|
||||
|
||||
@contextmanager
|
||||
def _cached(func):
|
||||
try:
|
||||
func.__cached__
|
||||
yield func
|
||||
except AttributeError:
|
||||
cache = {}
|
||||
|
||||
def wrapper(*args):
|
||||
try:
|
||||
return cache[args]
|
||||
except KeyError:
|
||||
value = cache[args] = func(*args)
|
||||
return value
|
||||
wrapper.__cached__ = True
|
||||
try:
|
||||
yield wrapper
|
||||
finally:
|
||||
cache.clear()
|
||||
|
||||
|
||||
def _make_selector(pattern_parts):
|
||||
pat = pattern_parts[0]
|
||||
child_parts = pattern_parts[1:]
|
||||
@@ -616,7 +576,6 @@ def _make_selector(pattern_parts):
|
||||
cls = _PreciseSelector
|
||||
return cls(pat, child_parts)
|
||||
|
||||
|
||||
if hasattr(functools, "lru_cache"):
|
||||
_make_selector = functools.lru_cache()(_make_selector)
|
||||
|
||||
@@ -630,10 +589,8 @@ class _Selector:
|
||||
self.child_parts = child_parts
|
||||
if child_parts:
|
||||
self.successor = _make_selector(child_parts)
|
||||
self.dironly = True
|
||||
else:
|
||||
self.successor = _TerminatingSelector()
|
||||
self.dironly = False
|
||||
|
||||
def select_from(self, parent_path):
|
||||
"""Iterate over all child paths of `parent_path` matched by this
|
||||
@@ -641,15 +598,13 @@ class _Selector:
|
||||
path_cls = type(parent_path)
|
||||
is_dir = path_cls.is_dir
|
||||
exists = path_cls.exists
|
||||
scandir = parent_path._accessor.scandir
|
||||
if not is_dir(parent_path):
|
||||
return iter([])
|
||||
return self._select_from(parent_path, is_dir, exists, scandir)
|
||||
listdir = parent_path._accessor.listdir
|
||||
return self._select_from(parent_path, is_dir, exists, listdir)
|
||||
|
||||
|
||||
class _TerminatingSelector:
|
||||
|
||||
def _select_from(self, parent_path, is_dir, exists, scandir):
|
||||
def _select_from(self, parent_path, is_dir, exists, listdir):
|
||||
yield parent_path
|
||||
|
||||
|
||||
@@ -659,20 +614,14 @@ class _PreciseSelector(_Selector):
|
||||
self.name = name
|
||||
_Selector.__init__(self, child_parts)
|
||||
|
||||
def _select_from(self, parent_path, is_dir, exists, scandir):
|
||||
def try_iter():
|
||||
path = parent_path._make_child_relpath(self.name)
|
||||
if (is_dir if self.dironly else exists)(path):
|
||||
for p in self.successor._select_from(
|
||||
path, is_dir, exists, scandir):
|
||||
yield p
|
||||
|
||||
def except_iter(exc):
|
||||
def _select_from(self, parent_path, is_dir, exists, listdir):
|
||||
if not is_dir(parent_path):
|
||||
return
|
||||
yield
|
||||
|
||||
for x in _try_except_permissionerror_iter(try_iter, except_iter):
|
||||
yield x
|
||||
path = parent_path._make_child_relpath(self.name)
|
||||
if exists(path):
|
||||
for p in self.successor._select_from(
|
||||
path, is_dir, exists, listdir):
|
||||
yield p
|
||||
|
||||
|
||||
class _WildcardSelector(_Selector):
|
||||
@@ -681,26 +630,17 @@ class _WildcardSelector(_Selector):
|
||||
self.pat = re.compile(fnmatch.translate(pat))
|
||||
_Selector.__init__(self, child_parts)
|
||||
|
||||
def _select_from(self, parent_path, is_dir, exists, scandir):
|
||||
def try_iter():
|
||||
cf = parent_path._flavour.casefold
|
||||
entries = list(scandir(parent_path))
|
||||
for entry in entries:
|
||||
if not self.dironly or entry.is_dir():
|
||||
name = entry.name
|
||||
casefolded = cf(name)
|
||||
if self.pat.match(casefolded):
|
||||
path = parent_path._make_child_relpath(name)
|
||||
for p in self.successor._select_from(
|
||||
path, is_dir, exists, scandir):
|
||||
yield p
|
||||
|
||||
def except_iter(exc):
|
||||
def _select_from(self, parent_path, is_dir, exists, listdir):
|
||||
if not is_dir(parent_path):
|
||||
return
|
||||
yield
|
||||
|
||||
for x in _try_except_permissionerror_iter(try_iter, except_iter):
|
||||
yield x
|
||||
cf = parent_path._flavour.casefold
|
||||
for name in listdir(parent_path):
|
||||
casefolded = cf(name)
|
||||
if self.pat.match(casefolded):
|
||||
path = parent_path._make_child_relpath(name)
|
||||
for p in self.successor._select_from(
|
||||
path, is_dir, exists, listdir):
|
||||
yield p
|
||||
|
||||
|
||||
class _RecursiveWildcardSelector(_Selector):
|
||||
@@ -708,46 +648,31 @@ class _RecursiveWildcardSelector(_Selector):
|
||||
def __init__(self, pat, child_parts):
|
||||
_Selector.__init__(self, child_parts)
|
||||
|
||||
def _iterate_directories(self, parent_path, is_dir, scandir):
|
||||
def _iterate_directories(self, parent_path, is_dir, listdir):
|
||||
yield parent_path
|
||||
for name in listdir(parent_path):
|
||||
path = parent_path._make_child_relpath(name)
|
||||
if is_dir(path):
|
||||
for p in self._iterate_directories(path, is_dir, listdir):
|
||||
yield p
|
||||
|
||||
def try_iter():
|
||||
entries = list(scandir(parent_path))
|
||||
for entry in entries:
|
||||
if entry.is_dir() and not entry.is_symlink():
|
||||
path = parent_path._make_child_relpath(entry.name)
|
||||
for p in self._iterate_directories(path, is_dir, scandir):
|
||||
yield p
|
||||
|
||||
def except_iter(exc):
|
||||
def _select_from(self, parent_path, is_dir, exists, listdir):
|
||||
if not is_dir(parent_path):
|
||||
return
|
||||
yield
|
||||
|
||||
for x in _try_except_permissionerror_iter(try_iter, except_iter):
|
||||
yield x
|
||||
|
||||
def _select_from(self, parent_path, is_dir, exists, scandir):
|
||||
def try_iter():
|
||||
with _cached(listdir) as listdir:
|
||||
yielded = set()
|
||||
try:
|
||||
successor_select = self.successor._select_from
|
||||
for starting_point in self._iterate_directories(
|
||||
parent_path, is_dir, scandir):
|
||||
parent_path, is_dir, listdir):
|
||||
for p in successor_select(
|
||||
starting_point, is_dir, exists, scandir):
|
||||
starting_point, is_dir, exists, listdir):
|
||||
if p not in yielded:
|
||||
yield p
|
||||
yielded.add(p)
|
||||
finally:
|
||||
yielded.clear()
|
||||
|
||||
def except_iter(exc):
|
||||
return
|
||||
yield
|
||||
|
||||
for x in _try_except_permissionerror_iter(try_iter, except_iter):
|
||||
yield x
|
||||
|
||||
|
||||
#
|
||||
# Public API
|
||||
@@ -818,25 +743,13 @@ class PurePath(object):
|
||||
for a in args:
|
||||
if isinstance(a, PurePath):
|
||||
parts += a._parts
|
||||
elif isinstance(a, basestring):
|
||||
# Force-cast str subclasses to str (issue #21127)
|
||||
parts.append(str(a))
|
||||
else:
|
||||
if sys.version_info >= (3, 6):
|
||||
a = os.fspath(a)
|
||||
else:
|
||||
# duck typing for older Python versions
|
||||
if hasattr(a, "__fspath__"):
|
||||
a = a.__fspath__()
|
||||
if isinstance(a, str):
|
||||
# Force-cast str subclasses to str (issue #21127)
|
||||
parts.append(str(a))
|
||||
# also handle unicode for PY2 (six.text_type = unicode)
|
||||
elif six.PY2 and isinstance(a, six.text_type):
|
||||
# cast to str using filesystem encoding
|
||||
parts.append(a.encode(sys.getfilesystemencoding()))
|
||||
else:
|
||||
raise TypeError(
|
||||
"argument should be a str object or an os.PathLike "
|
||||
"object returning str, not %r"
|
||||
% type(a))
|
||||
raise TypeError(
|
||||
"argument should be a path or str object, not %r"
|
||||
% type(a))
|
||||
return cls._flavour.parse_parts(parts)
|
||||
|
||||
@classmethod
|
||||
@@ -870,7 +783,7 @@ class PurePath(object):
|
||||
return cls._flavour.join(parts)
|
||||
|
||||
def _init(self):
|
||||
# Overridden in concrete Path
|
||||
# Overriden in concrete Path
|
||||
pass
|
||||
|
||||
def _make_child(self, args):
|
||||
@@ -889,9 +802,6 @@ class PurePath(object):
|
||||
self._parts) or '.'
|
||||
return self._str
|
||||
|
||||
def __fspath__(self):
|
||||
return str(self)
|
||||
|
||||
def as_posix(self):
|
||||
"""Return the string representation of the path with forward (/)
|
||||
slashes."""
|
||||
@@ -1072,7 +982,7 @@ class PurePath(object):
|
||||
cf = self._flavour.casefold_parts
|
||||
if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
|
||||
formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
|
||||
raise ValueError("{0!r} does not start with {1!r}"
|
||||
raise ValueError("{!r} does not start with {!r}"
|
||||
.format(str(self), str(formatted)))
|
||||
return self._from_parsed_parts('', root if n == 1 else '',
|
||||
abs_parts[n:])
|
||||
@@ -1160,12 +1070,6 @@ class PurePath(object):
|
||||
return True
|
||||
|
||||
|
||||
# Can't subclass os.PathLike from PurePath and keep the constructor
|
||||
# optimizations in PurePath._parse_args().
|
||||
if sys.version_info >= (3, 6):
|
||||
os.PathLike.register(PurePath)
|
||||
|
||||
|
||||
class PurePosixPath(PurePath):
|
||||
_flavour = _posix_flavour
|
||||
__slots__ = ()
|
||||
@@ -1252,8 +1156,8 @@ class Path(PurePath):
|
||||
return cls(cls()._flavour.gethomedir(None))
|
||||
|
||||
def samefile(self, other_path):
|
||||
"""Return whether other_path is the same or not as this file
|
||||
(as returned by os.path.samefile()).
|
||||
"""Return whether `other_file` is the same or not as this file.
|
||||
(as returned by os.path.samefile(file, other_file)).
|
||||
"""
|
||||
if hasattr(os.path, "samestat"):
|
||||
st = self.stat()
|
||||
@@ -1287,8 +1191,6 @@ class Path(PurePath):
|
||||
"""Iterate over this subtree and yield all existing files (of any
|
||||
kind, including directories) matching the given pattern.
|
||||
"""
|
||||
if not pattern:
|
||||
raise ValueError("Unacceptable pattern: {0!r}".format(pattern))
|
||||
pattern = self._flavour.casefold(pattern)
|
||||
drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
|
||||
if drv or root:
|
||||
@@ -1327,7 +1229,7 @@ class Path(PurePath):
|
||||
obj._init(template=self)
|
||||
return obj
|
||||
|
||||
def resolve(self, strict=False):
|
||||
def resolve(self):
|
||||
"""
|
||||
Make the path absolute, resolving all symlinks on the way and also
|
||||
normalizing it (for example turning slashes into backslashes under
|
||||
@@ -1335,7 +1237,7 @@ class Path(PurePath):
|
||||
"""
|
||||
if self._closed:
|
||||
self._raise_closed()
|
||||
s = self._flavour.resolve(self, strict=strict)
|
||||
s = self._flavour.resolve(self)
|
||||
if s is None:
|
||||
# No symlink resolution => for consistency, raise an error if
|
||||
# the path doesn't exist or is forbidden
|
||||
@@ -1405,7 +1307,7 @@ class Path(PurePath):
|
||||
if not isinstance(data, six.binary_type):
|
||||
raise TypeError(
|
||||
'data must be %s, not %s' %
|
||||
(six.binary_type.__name__, data.__class__.__name__))
|
||||
(six.binary_type.__class__.__name__, data.__class__.__name__))
|
||||
with self.open(mode='wb') as f:
|
||||
return f.write(data)
|
||||
|
||||
@@ -1416,7 +1318,7 @@ class Path(PurePath):
|
||||
if not isinstance(data, six.text_type):
|
||||
raise TypeError(
|
||||
'data must be %s, not %s' %
|
||||
(six.text_type.__name__, data.__class__.__name__))
|
||||
(six.text_type.__class__.__name__, data.__class__.__name__))
|
||||
with self.open(mode='w', encoding=encoding, errors=errors) as f:
|
||||
return f.write(data)
|
||||
|
||||
@@ -1444,26 +1346,27 @@ class Path(PurePath):
|
||||
os.close(fd)
|
||||
|
||||
def mkdir(self, mode=0o777, parents=False, exist_ok=False):
|
||||
"""
|
||||
Create a new directory at this given path.
|
||||
"""
|
||||
|
||||
def helper(exc):
|
||||
if not exist_ok or not self.is_dir():
|
||||
raise exc
|
||||
|
||||
if self._closed:
|
||||
self._raise_closed()
|
||||
|
||||
def _try_func():
|
||||
self._accessor.mkdir(self, mode)
|
||||
|
||||
def _exc_func(exc):
|
||||
if not parents or self.parent == self:
|
||||
raise exc
|
||||
self.parent.mkdir(parents=True, exist_ok=True)
|
||||
self.mkdir(mode, parents=False, exist_ok=exist_ok)
|
||||
|
||||
try:
|
||||
_try_except_filenotfounderror(_try_func, _exc_func)
|
||||
except OSError:
|
||||
if not exist_ok or not self.is_dir():
|
||||
raise
|
||||
if not parents:
|
||||
_try_except_fileexistserror(
|
||||
lambda: self._accessor.mkdir(self, mode),
|
||||
helper)
|
||||
else:
|
||||
try:
|
||||
_try_except_fileexistserror(
|
||||
lambda: self._accessor.mkdir(self, mode),
|
||||
helper)
|
||||
except OSError as e:
|
||||
if e.errno != ENOENT:
|
||||
raise
|
||||
self.parent.mkdir(parents=True)
|
||||
self._accessor.mkdir(self, mode)
|
||||
|
||||
def chmod(self, mode):
|
||||
"""
|
||||
@@ -1661,9 +1564,3 @@ class PosixPath(Path, PurePosixPath):
|
||||
|
||||
class WindowsPath(Path, PureWindowsPath):
|
||||
__slots__ = ()
|
||||
|
||||
def owner(self):
|
||||
raise NotImplementedError("Path.owner() is unsupported on this system")
|
||||
|
||||
def group(self):
|
||||
raise NotImplementedError("Path.group() is unsupported on this system")
|
||||
|
||||
@@ -22,9 +22,9 @@ required = [
|
||||
'setuptools>=36.2.1',
|
||||
'virtualenv-clone>=0.2.5',
|
||||
'virtualenv',
|
||||
'pathlib;python_version<"3.4"',
|
||||
'requests[security];python_version<"3.0"',
|
||||
'ordereddict;python_version<"3.0"',
|
||||
'pathlib2==2.1.0; python_version<"3.4"',
|
||||
'requests[security]; python_version<"3.0"',
|
||||
'ordereddict; python_version<"3.0"',
|
||||
]
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,49 @@
|
||||
import pytest
|
||||
|
||||
from pipenv.cmdparse import Script, ScriptEmptyError
|
||||
|
||||
|
||||
@pytest.mark.run
|
||||
@pytest.mark.script
|
||||
def test_parse():
|
||||
script = Script.parse(['python', '-c', "print('hello')"])
|
||||
assert script.command == 'python'
|
||||
assert script.args == ['-c', "print('hello')"], script
|
||||
|
||||
|
||||
@pytest.mark.run
|
||||
@pytest.mark.script
|
||||
def test_parse_error():
|
||||
with pytest.raises(ScriptEmptyError) as e:
|
||||
Script.parse('')
|
||||
assert str(e.value) == "[]"
|
||||
|
||||
|
||||
@pytest.mark.run
|
||||
def test_extend():
|
||||
script = Script('python', ['-c', "print('hello')"])
|
||||
script.extend(['--verbose'])
|
||||
assert script.command == 'python'
|
||||
assert script.args == ['-c', "print('hello')", "--verbose"], script
|
||||
|
||||
|
||||
@pytest.mark.run
|
||||
@pytest.mark.script
|
||||
def test_cmdify():
|
||||
script = Script('python', ['-c', "print('hello')"])
|
||||
cmd = script.cmdify()
|
||||
assert cmd == '"python" "-c" "print(\'hello\')"', script
|
||||
|
||||
|
||||
@pytest.mark.run
|
||||
@pytest.mark.script
|
||||
def test_cmdify_complex():
|
||||
script = Script.parse(' '.join([
|
||||
'"C:\\Program Files\\Python36\\python.exe" -c',
|
||||
""" "print(\'Double quote: \\\"\')" """.strip(),
|
||||
]))
|
||||
assert script.cmdify() == ' '.join([
|
||||
'"C:\\Program Files\\Python36\\python.exe"',
|
||||
'"-c"',
|
||||
""" "print(\'Double quote: \\\"\')" """.strip(),
|
||||
]), script
|
||||
+80
-46
@@ -5,7 +5,7 @@ import shutil
|
||||
import json
|
||||
import pytest
|
||||
import warnings
|
||||
from pipenv.core import activate_virtualenv, _get_command_posix
|
||||
from pipenv.core import activate_virtualenv
|
||||
from pipenv.utils import (
|
||||
temp_environ, get_windows_path, mkdir_p, normalize_drive, TemporaryDirectory
|
||||
)
|
||||
@@ -15,6 +15,7 @@ from pipenv.vendor import requests
|
||||
from pipenv.patched import pipfile
|
||||
from pipenv.project import Project
|
||||
from pipenv.vendor.six import PY2
|
||||
from flaky import flaky
|
||||
if PY2:
|
||||
class ResourceWarning(Warning):
|
||||
pass
|
||||
@@ -237,8 +238,16 @@ class TestPipenv:
|
||||
@pytest.mark.install
|
||||
def test_install_parse_error(self, pypi):
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
|
||||
# Make sure unparseable packages don't wind up in the pipfile
|
||||
# Escape $ for shell input
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
contents = """
|
||||
[packages]
|
||||
|
||||
[dev-packages]
|
||||
""".strip()
|
||||
f.write(contents)
|
||||
c = p.pipenv('install requests u/\\/p@r\$34b13+pkg')
|
||||
assert c.return_code != 0
|
||||
assert 'u/\\/p@r$34b13+pkg' not in p.pipfile['packages']
|
||||
@@ -271,7 +280,9 @@ class TestPipenv:
|
||||
assert 'urllib3' in p.lockfile['default']
|
||||
assert 'certifi' in p.lockfile['default']
|
||||
|
||||
@pytest.mark.complex_lock
|
||||
@pytest.mark.complex
|
||||
@pytest.mark.lock
|
||||
@pytest.mark.skip(reason='Does not work')
|
||||
def test_complex_lock(self, pypi):
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
c = p.pipenv('install apscheduler')
|
||||
@@ -299,9 +310,10 @@ class TestPipenv:
|
||||
|
||||
@pytest.mark.dev
|
||||
@pytest.mark.install
|
||||
@flaky
|
||||
def test_install_without_dev(self, pypi):
|
||||
"""Ensure that running `pipenv install` doesn't install dev packages"""
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
with PipenvInstance(pypi=pypi, chdir=True) as p:
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
contents = """
|
||||
[packages]
|
||||
@@ -324,6 +336,7 @@ records = "*"
|
||||
|
||||
@pytest.mark.cli
|
||||
@pytest.mark.install
|
||||
@flaky
|
||||
def test_install_without_dev_section(self, pypi):
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
@@ -419,8 +432,9 @@ tablib = "*"
|
||||
|
||||
@pytest.mark.extras
|
||||
@pytest.mark.install
|
||||
@flaky
|
||||
def test_extras_install(self, pypi):
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
with PipenvInstance(pypi=pypi, chdir=True) as p:
|
||||
c = p.pipenv('install requests[socks]')
|
||||
assert c.return_code == 0
|
||||
assert 'requests' in p.pipfile['packages']
|
||||
@@ -469,8 +483,9 @@ setup(
|
||||
@pytest.mark.vcs
|
||||
@pytest.mark.install
|
||||
@needs_internet
|
||||
@flaky
|
||||
def test_basic_vcs_install(self, pip_src_dir, pypi):
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
with PipenvInstance(pypi=pypi, chdir=True) as p:
|
||||
c = p.pipenv('install git+https://github.com/requests/requests.git#egg=requests')
|
||||
assert c.return_code == 0
|
||||
# edge case where normal package starts with VCS name shouldn't be flagged as vcs
|
||||
@@ -485,6 +500,7 @@ setup(
|
||||
@pytest.mark.vcs
|
||||
@pytest.mark.install
|
||||
@needs_internet
|
||||
@flaky
|
||||
def test_editable_vcs_install(self, pip_src_dir, pypi):
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
c = p.pipenv('install -e git+https://github.com/requests/requests.git#egg=requests')
|
||||
@@ -500,6 +516,7 @@ setup(
|
||||
|
||||
@pytest.mark.install
|
||||
@pytest.mark.pin
|
||||
@flaky
|
||||
def test_windows_pinned_pipfile(self, pypi):
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
@@ -515,11 +532,12 @@ tablib = "<0.12"
|
||||
|
||||
@pytest.mark.run
|
||||
@pytest.mark.install
|
||||
@flaky
|
||||
def test_multiprocess_bug_and_install(self, pypi):
|
||||
with temp_environ():
|
||||
os.environ['PIPENV_MAX_SUBPROCESS'] = '2'
|
||||
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
with PipenvInstance(pypi=pypi, chdir=True) as p:
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
contents = """
|
||||
[packages]
|
||||
@@ -545,9 +563,10 @@ tpfd = "*"
|
||||
|
||||
@pytest.mark.sequential
|
||||
@pytest.mark.install
|
||||
@flaky
|
||||
def test_sequential_mode(self, pypi):
|
||||
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
with PipenvInstance(pypi=pypi, chdir=True) as p:
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
contents = """
|
||||
[packages]
|
||||
@@ -575,6 +594,7 @@ tpfd = "*"
|
||||
@pytest.mark.resolver
|
||||
@pytest.mark.backup_resolver
|
||||
@needs_internet
|
||||
@flaky
|
||||
def test_backup_resolver(self):
|
||||
with PipenvInstance() as p:
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
@@ -590,6 +610,7 @@ tpfd = "*"
|
||||
|
||||
@pytest.mark.run
|
||||
@pytest.mark.markers
|
||||
@flaky
|
||||
def test_package_environment_markers(self, pypi):
|
||||
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
@@ -611,6 +632,7 @@ tablib = {version = "*", markers="os_name=='splashwear'"}
|
||||
@pytest.mark.run
|
||||
@pytest.mark.alt
|
||||
@pytest.mark.install
|
||||
@flaky
|
||||
def test_specific_package_environment_markers(self, pypi):
|
||||
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
@@ -632,6 +654,7 @@ requests = {version = "*", os_name = "== 'splashwear'"}
|
||||
|
||||
@pytest.mark.markers
|
||||
@pytest.mark.install
|
||||
@flaky
|
||||
def test_top_level_overrides_environment_markers(self, pypi):
|
||||
"""Top-level environment markers should take precedence.
|
||||
"""
|
||||
@@ -651,6 +674,7 @@ funcsigs = {version = "*", os_name = "== 'splashwear'"}
|
||||
|
||||
@pytest.mark.markers
|
||||
@pytest.mark.install
|
||||
@flaky
|
||||
def test_global_overrides_environment_markers(self, pypi):
|
||||
"""Empty (unconditional) dependency should take precedence.
|
||||
|
||||
@@ -677,6 +701,7 @@ funcsigs = "*"
|
||||
@pytest.mark.vcs
|
||||
@pytest.mark.tablib
|
||||
@needs_internet
|
||||
@flaky
|
||||
def test_install_editable_git_tag(self, pip_src_dir):
|
||||
# This uses the real PyPI since we need Internet to access the Git
|
||||
# dependency anyway.
|
||||
@@ -691,7 +716,7 @@ funcsigs = "*"
|
||||
|
||||
@pytest.mark.run
|
||||
@pytest.mark.alt
|
||||
@pytest.mark.install
|
||||
@flaky
|
||||
def test_alternative_version_specifier(self, pypi):
|
||||
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
@@ -733,23 +758,20 @@ requests = {version = "*"}
|
||||
|
||||
assert normalize_drive(p.path) in p.pipenv('--venv').out
|
||||
|
||||
@pytest.mark.dotenv
|
||||
@pytest.mark.dotvenv
|
||||
def test_venv_at_project_root(self):
|
||||
def _assert_venv_at_project_root(p):
|
||||
c = p.pipenv('--venv')
|
||||
assert c.return_code == 0
|
||||
assert p.path in c.out
|
||||
|
||||
with temp_environ():
|
||||
with PipenvInstance(chdir=True, pipfile=False) as p:
|
||||
with PipenvInstance(chdir=True) as p:
|
||||
os.environ['PIPENV_VENV_IN_PROJECT'] = '1'
|
||||
c = p.pipenv('install')
|
||||
assert c.return_code == 0
|
||||
_assert_venv_at_project_root(p)
|
||||
assert normalize_drive(p.path) in p.pipenv('--venv').out
|
||||
del os.environ['PIPENV_VENV_IN_PROJECT']
|
||||
os.mkdir('subdir')
|
||||
os.chdir('subdir')
|
||||
# should still detect installed
|
||||
_assert_venv_at_project_root(p)
|
||||
assert normalize_drive(p.path) in p.pipenv('--venv').out
|
||||
|
||||
@pytest.mark.dotvenv
|
||||
def test_reuse_previous_venv(self, pypi):
|
||||
@@ -794,9 +816,8 @@ requests = {version = "*"}
|
||||
# If we can do this we can theoretically make a subshell
|
||||
# This test doesn't work on *nix
|
||||
if os.name == 'nt':
|
||||
args = ['pewtwo', 'in', '.venv', 'pip', 'freeze']
|
||||
process = subprocess.Popen(
|
||||
args,
|
||||
'pewtwo in .venv pip freeze',
|
||||
shell=True,
|
||||
universal_newlines=True,
|
||||
stdin=subprocess.PIPE,
|
||||
@@ -901,6 +922,7 @@ import records
|
||||
|
||||
@pytest.mark.code
|
||||
@pytest.mark.virtualenv
|
||||
@pytest.mark.project
|
||||
def test_activate_virtualenv_no_source(self):
|
||||
command = activate_virtualenv(source=False)
|
||||
venv = Project().virtualenv_location
|
||||
@@ -908,6 +930,7 @@ import records
|
||||
assert command == '{0}/bin/activate'.format(venv)
|
||||
|
||||
@pytest.mark.lock
|
||||
@pytest.mark.requirements
|
||||
def test_lock_handle_eggs(self, pypi):
|
||||
"""Ensure locking works with packages provoding egg formats.
|
||||
"""
|
||||
@@ -964,7 +987,7 @@ flask = "==0.12.2"
|
||||
click = "==6.7"
|
||||
|
||||
[dev-packages]
|
||||
requests = {git = "https://github.com/requests/requests", egg = "requests"}
|
||||
requests = {git = "https://github.com/requests/requests.git"}
|
||||
""".strip()
|
||||
f.write(contents)
|
||||
|
||||
@@ -1005,13 +1028,13 @@ allow_prereleases = true
|
||||
assert p.lockfile['default']['sqlalchemy']['version'] == '==1.2.0b3'
|
||||
|
||||
@pytest.mark.lock
|
||||
@pytest.mark.requirements
|
||||
@pytest.mark.complex
|
||||
@pytest.mark.maya
|
||||
@needs_internet
|
||||
def test_complex_deps_lock_and_install_properly(self):
|
||||
@flaky
|
||||
def test_complex_deps_lock_and_install_properly(self, pip_src_dir, pypi):
|
||||
# This uses the real PyPI because Maya has too many dependencies...
|
||||
with PipenvInstance() as p:
|
||||
with PipenvInstance(chdir=True, pypi=pypi) as p:
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
contents = """
|
||||
[packages]
|
||||
@@ -1019,7 +1042,7 @@ maya = "*"
|
||||
""".strip()
|
||||
f.write(contents)
|
||||
|
||||
c = p.pipenv('lock')
|
||||
c = p.pipenv('lock --verbose')
|
||||
assert c.return_code == 0
|
||||
|
||||
c = p.pipenv('install')
|
||||
@@ -1028,6 +1051,7 @@ maya = "*"
|
||||
@pytest.mark.extras
|
||||
@pytest.mark.lock
|
||||
@pytest.mark.complex
|
||||
@pytest.mark.skip(reason='This is toooo flaky; need to mock this')
|
||||
@needs_internet
|
||||
def test_complex_lock_deep_extras(self):
|
||||
# records[pandas] requires tablib[pandas] which requires pandas.
|
||||
@@ -1050,6 +1074,7 @@ records = {extras = ["pandas"], version = "==0.5.2"}
|
||||
|
||||
@pytest.mark.lock
|
||||
@pytest.mark.deploy
|
||||
@pytest.mark.cli
|
||||
def test_deploy_works(self, pypi):
|
||||
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
@@ -1080,27 +1105,26 @@ requests = "==2.14.0"
|
||||
@pytest.mark.files
|
||||
@pytest.mark.urls
|
||||
@needs_internet
|
||||
@flaky
|
||||
def test_urls_work(self, pypi):
|
||||
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
with PipenvInstance(chdir=True, pypi=pypi) as p:
|
||||
|
||||
c = p.pipenv('install https://github.com/divio/django-cms/archive/release/3.4.x.zip')
|
||||
key = [k for k in p.pipfile['packages'].keys()][0]
|
||||
dep = p.pipfile['packages'][key]
|
||||
|
||||
assert 'file' in dep
|
||||
assert c.return_code == 0
|
||||
|
||||
key = [k for k in p.lockfile['default'].keys()][0]
|
||||
dep = p.lockfile['default'][key]
|
||||
dep = list(p.pipfile['packages'].values())[0]
|
||||
assert 'file' in dep, p.pipfile
|
||||
|
||||
assert 'file' in dep
|
||||
dep = list(p.lockfile['default'].values())[0]
|
||||
assert 'file' in dep, p.lockfile
|
||||
|
||||
@pytest.mark.install
|
||||
@pytest.mark.files
|
||||
@pytest.mark.resolver
|
||||
@pytest.mark.eggs
|
||||
def test_local_package(self, pip_src_dir):
|
||||
@flaky
|
||||
def test_local_package(self, pip_src_dir, pypi):
|
||||
"""This test ensures that local packages (directories with a setup.py)
|
||||
installed in editable mode have their dependencies resolved as well"""
|
||||
file_name = 'tablib-0.12.1.tar.gz'
|
||||
@@ -1108,7 +1132,7 @@ requests = "==2.14.0"
|
||||
# Not sure where travis/appveyor run tests from
|
||||
test_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
source_path = os.path.abspath(os.path.join(test_dir, 'test_artifacts', file_name))
|
||||
with PipenvInstance() as p:
|
||||
with PipenvInstance(chdir=True, pypi=pypi) as p:
|
||||
# This tests for a bug when installing a zipfile in the current dir
|
||||
copy_to = os.path.join(p.path, file_name)
|
||||
shutil.copy(source_path, copy_to)
|
||||
@@ -1121,13 +1145,14 @@ requests = "==2.14.0"
|
||||
|
||||
@pytest.mark.install
|
||||
@pytest.mark.files
|
||||
def test_local_zipfiles(self):
|
||||
@flaky
|
||||
def test_local_zipfiles(self, pypi):
|
||||
file_name = 'tablib-0.12.1.tar.gz'
|
||||
# Not sure where travis/appveyor run tests from
|
||||
test_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
source_path = os.path.abspath(os.path.join(test_dir, 'test_artifacts', file_name))
|
||||
|
||||
with PipenvInstance() as p:
|
||||
with PipenvInstance(chdir=True, pypi=pypi) as p:
|
||||
# This tests for a bug when installing a zipfile in the current dir
|
||||
shutil.copy(source_path, os.path.join(p.path, file_name))
|
||||
|
||||
@@ -1148,6 +1173,7 @@ requests = "==2.14.0"
|
||||
@pytest.mark.files
|
||||
@pytest.mark.urls
|
||||
@needs_internet
|
||||
@flaky
|
||||
def test_install_remote_requirements(self, pypi):
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
# using a github hosted requirements.txt file
|
||||
@@ -1166,6 +1192,7 @@ requests = "==2.14.0"
|
||||
|
||||
@pytest.mark.install
|
||||
@pytest.mark.files
|
||||
@flaky
|
||||
def test_relative_paths(self, pypi):
|
||||
file_name = 'tablib-0.12.1.tar.gz'
|
||||
test_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)))
|
||||
@@ -1187,6 +1214,7 @@ requests = "==2.14.0"
|
||||
|
||||
@pytest.mark.install
|
||||
@pytest.mark.local_file
|
||||
@flaky
|
||||
def test_install_local_file_collision(self, pypi):
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
target_package = 'alembic'
|
||||
@@ -1199,13 +1227,15 @@ requests = "==2.14.0"
|
||||
assert p.pipfile['packages'][target_package] == '*'
|
||||
assert target_package in p.lockfile['default']
|
||||
|
||||
@pytest.mark.cli
|
||||
@pytest.mark.clean
|
||||
def test_clean_on_empty_venv(self, pypi):
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
c = p.pipenv('clean')
|
||||
assert c.return_code == 0
|
||||
|
||||
@pytest.mark.install
|
||||
@pytest.mark.project
|
||||
@flaky
|
||||
def test_environment_variable_value_does_not_change_hash(self, pypi):
|
||||
with PipenvInstance(chdir=True, pypi=pypi) as p:
|
||||
with temp_environ():
|
||||
@@ -1255,21 +1285,25 @@ multicommand = "bash -c \"cd docs && make html\""
|
||||
assert c.return_code == 0
|
||||
assert c.out == 'foo\n'
|
||||
assert c.err == ''
|
||||
if os.name != 'nt':
|
||||
c = p.pipenv('run notfoundscript')
|
||||
assert c.return_code == 1
|
||||
assert c.out == ''
|
||||
|
||||
c = p.pipenv('run notfoundscript')
|
||||
assert c.return_code == 1
|
||||
assert c.out == ''
|
||||
if os.name != 'nt': # TODO: Implement this message for Windows.
|
||||
assert 'Error' in c.err
|
||||
assert 'randomthingtotally (from notfoundscript)' in c.err
|
||||
executable, argv = _get_command_posix(Project(), 'multicommand', [])
|
||||
assert executable == 'bash'
|
||||
assert argv == ['-c', 'cd docs && make html']
|
||||
executable, argv = _get_command_posix(Project(), 'appendscript', ['a', 'b'])
|
||||
assert executable == 'cmd'
|
||||
assert argv == ['arg1', 'a', 'b']
|
||||
|
||||
project = Project()
|
||||
script = project.build_script('multicommand')
|
||||
assert script.command == 'bash'
|
||||
assert script.args == ['-c', 'cd docs && make html']
|
||||
script = project.build_script('appendscript', ['a', 'b'])
|
||||
assert script.command == 'cmd'
|
||||
assert script.args == ['arg1', 'a', 'b']
|
||||
|
||||
@pytest.mark.lock
|
||||
@pytest.mark.complex
|
||||
@flaky
|
||||
@py3_only
|
||||
def test_resolver_unique_markers(self, pypi):
|
||||
"""vcrpy has a dependency on `yarl` which comes with a marker
|
||||
|
||||
Reference in New Issue
Block a user