diff --git a/.azure-pipelines/docs.yml b/.azure-pipelines/docs.yml new file mode 100644 index 00000000..b65fdfb4 --- /dev/null +++ b/.azure-pipelines/docs.yml @@ -0,0 +1,21 @@ +jobs: +- job: + displayName: Docs + pool: + vmImage: ubuntu-16.04 + + steps: + - task: UsePythonVersion@0 + inputs: + versionSpec: '3.7' + + - template: steps/install-dependencies.yml + + - bash: tox -e docs + displayName: Build docs + + - task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact: docs' + inputs: + pathToPublish: docs/build + artifactName: docs diff --git a/.azure-pipelines/jobs/run-manifest-check.yml b/.azure-pipelines/jobs/run-manifest-check.yml new file mode 100644 index 00000000..6d0b97eb --- /dev/null +++ b/.azure-pipelines/jobs/run-manifest-check.yml @@ -0,0 +1,14 @@ +steps: +- task: UsePythonVersion@0 + displayName: Use Python $(python.version) + inputs: + versionSpec: '$(python.version)' + architecture: '$(python.architecture)' + +- template: ../steps/install-dependencies.yml + +- bash: | + export GIT_SSL_CAINFO=$(python -m certifi) + export LANG=C.UTF-8 + python -m pip install check-manifest + check-manifest diff --git a/.azure-pipelines/jobs/run-tests-windows.yml b/.azure-pipelines/jobs/run-tests-windows.yml new file mode 100644 index 00000000..6b6f86fa --- /dev/null +++ b/.azure-pipelines/jobs/run-tests-windows.yml @@ -0,0 +1,12 @@ +steps: +- task: UsePythonVersion@0 + displayName: Use Python $(python.version) + inputs: + versionSpec: '$(python.version)' + architecture: '$(python.architecture)' + +- template: ../steps/install-dependencies.yml + +- template: ../steps/create-virtualenv.yml + +- template: ../steps/run-tests.yml diff --git a/.azure-pipelines/jobs/run-tests.yml b/.azure-pipelines/jobs/run-tests.yml new file mode 100644 index 00000000..fe98e8ec --- /dev/null +++ b/.azure-pipelines/jobs/run-tests.yml @@ -0,0 +1,37 @@ +steps: +- task: UsePythonVersion@0 + displayName: Use Python $(python.version) + inputs: + versionSpec: '$(python.version)' + architecture: '$(python.architecture)' + +- template: ../steps/install-dependencies.yml + +- bash: | + mkdir -p "$AGENT_HOMEDIRECTORY/.virtualenvs" + mkdir -p "$WORKON_HOME" + pip install certifi + export GIT_SSL_CAINFO="$(python -m certifi)" + export LANG="C.UTF-8" + export PIP_PROCESS_DEPENDENCY_LINKS="1" + echo "Path $PATH" + echo "Installing Pipenv…" + pip install -e "$(pwd)" --upgrade + pipenv install --deploy --dev + echo pipenv --venv && echo pipenv --py && echo pipenv run python --version + displayName: Make Virtualenv + +- script: | + # Fix Git SSL errors + export GIT_SSL_CAINFO="$(python -m certifi)" + export LANG="C.UTF-8" + export PIP_PROCESS_DEPENDENCY_LINKS="1" + pipenv run pytest --junitxml=test-results.xml + displayName: Run integration tests + +- task: PublishTestResults@2 + displayName: Publish Test Results + inputs: + testResultsFiles: '**/test-results.xml' + testRunTitle: 'Python $(python.version)' + condition: succeededOrFailed() diff --git a/.azure-pipelines/jobs/run-vendor-scripts.yml b/.azure-pipelines/jobs/run-vendor-scripts.yml new file mode 100644 index 00000000..7fe75731 --- /dev/null +++ b/.azure-pipelines/jobs/run-vendor-scripts.yml @@ -0,0 +1,39 @@ +parameters: + vmImage: + +jobs: +- job: Vendor_Scripts + displayName: Test Vendor Scripts + pool: + vmImage: ${{ parameters.vmImage }} + strategy: + maxParallel: 4 + matrix: + ${{ if eq(parameters.vmImage, 'vs2017-win2016') }}: + # TODO remove once vs2017-win2016 has Python 3.7 + Python37: + python.version: '>= 3.7.0-b2' + python.architecture: x64 + ${{ if ne(parameters.vmImage, 'vs2017-win2016' )}}: + Python37: + python.version: '>= 3.7' + python.architecture: x64 + steps: + - task: UsePythonVersion@0 + displayName: Use Python $(python.version) + inputs: + versionSpec: '$(python.version)' + architecture: '$(python.architecture)' + + - template: ../steps/install-dependencies.yml + + - bash: | + mkdir -p "$AGENT_HOMEDIRECTORY/.virtualenvs" + mkdir -p "$WORKON_HOME" + pip install certifi + export GIT_SSL_CAINFO=$(python -m certifi) + export LANG=C.UTF-8 + python -m pip install --upgrade invoke requests parver + python -m invoke vendoring.update + + - template: ./run-manifest-check.yml diff --git a/.azure-pipelines/jobs/test.yml b/.azure-pipelines/jobs/test.yml new file mode 100644 index 00000000..150937ef --- /dev/null +++ b/.azure-pipelines/jobs/test.yml @@ -0,0 +1,48 @@ +parameters: + vmImage: + +jobs: +- job: Test_Primary + displayName: Test Primary + pool: + vmImage: ${{ parameters.vmImage }} + strategy: + maxParallel: 4 + matrix: + Python27: + python.version: '2.7' + python.architecture: x64 + ${{ if eq(parameters.vmImage, 'vs2017-win2016') }}: + # TODO remove once vs2017-win2016 has Python 3.7 + Python37: + python.version: '>= 3.7.0-b2' + python.architecture: x64 + ${{ if ne(parameters.vmImage, 'vs2017-win2016' )}}: + Python37: + python.version: '>= 3.7' + python.architecture: x64 + steps: + - ${{ if eq(parameters.vmImage, 'vs2017-win2016') }}: + - template: ./run-tests-windows.yml + + - ${{ if ne(parameters.vmImage, 'vs2017-win2016') }}: + - template: ./run-tests.yml + +- job: Test_Secondary + displayName: Test python3.6 + # Run after Test_Primary so we don't devour time and jobs if tests are going to fail + # dependsOn: Test_Primary + pool: + vmImage: ${{ parameters.vmImage }} + strategy: + maxParallel: 4 + matrix: + Python36: + python.version: '3.6' + python.architecture: x64 + steps: + - ${{ if eq(parameters.vmImage, 'vs2017-win2016') }}: + - template: ./run-tests-windows.yml + + - ${{ if ne(parameters.vmImage, 'vs2017-win2016') }}: + - template: ./run-tests.yml diff --git a/.azure-pipelines/linux.yml b/.azure-pipelines/linux.yml new file mode 100644 index 00000000..a2f34d4c --- /dev/null +++ b/.azure-pipelines/linux.yml @@ -0,0 +1,27 @@ +name: Pipenv Build Rules +trigger: + batch: true + branches: + include: + - master + paths: + exclude: + - docs/* + - news/* + - README.md + - pipenv/*.txt + - CHANGELOG.rst + - CONTRIBUTING.md + - CODE_OF_CONDUCT.md + - .gitignore + - .gitattributes + - .editorconfig + +jobs: +- template: jobs/test.yml + parameters: + vmImage: ubuntu-16.04 + +- template: jobs/run-vendor-scripts.yml + parameters: + vmImage: ubuntu-16.04 diff --git a/.azure-pipelines/steps/create-virtualenv.yml b/.azure-pipelines/steps/create-virtualenv.yml new file mode 100644 index 00000000..9d1a6903 --- /dev/null +++ b/.azure-pipelines/steps/create-virtualenv.yml @@ -0,0 +1,6 @@ +steps: +- script: | + virtualenv D:\.venv + D:\.venv\Scripts\pip.exe install -e . && D:\.venv\Scripts\pipenv install --dev + echo D:\.venv\Scripts\pipenv --venv && echo D:\.venv\Scripts\pipenv --py && echo D:\.venv\Scripts\pipenv run python --version + displayName: Make Virtualenv diff --git a/.azure-pipelines/steps/install-dependencies.yml b/.azure-pipelines/steps/install-dependencies.yml new file mode 100644 index 00000000..dfe733b6 --- /dev/null +++ b/.azure-pipelines/steps/install-dependencies.yml @@ -0,0 +1,3 @@ +steps: +- script: 'python -m pip install --upgrade pip && python -m pip install -e .' + displayName: Upgrade Pip & Install Pipenv diff --git a/.azure-pipelines/steps/run-tests.yml b/.azure-pipelines/steps/run-tests.yml new file mode 100644 index 00000000..a7b99a13 --- /dev/null +++ b/.azure-pipelines/steps/run-tests.yml @@ -0,0 +1,23 @@ +steps: +- powershell: | + # Fix Git SSL errors + pip install certifi + python -m certifi > cacert.txt + Write-Host "##vso[task.setvariable variable=GIT_SSL_CAINFO]$(Get-Content cacert.txt)" + $env:GIT_SSL_CAINFO="$(Get-Content cacert.txt)" + # Shorten paths to get under MAX_PATH or else integration tests will fail + # https://bugs.python.org/issue18199 + subst T: "$env:TEMP" + Write-Host "##vso[task.setvariable variable=TEMP]T:\" + $env:TEMP='T:\' + Write-Host "##vso[task.setvariable variable=TMP]T:\" + $env:TEMP='T:\' + D:\.venv\Scripts\pipenv run pytest -ra --ignore=pipenv\patched --ignore=pipenv\vendor --junitxml=test-results.xml tests + displayName: Run integration tests + +- task: PublishTestResults@2 + displayName: Publish Test Results + inputs: + testResultsFiles: '**/test-results.xml' + testRunTitle: 'Python $(python.version)' + condition: succeededOrFailed() diff --git a/.azure-pipelines/windows.yml b/.azure-pipelines/windows.yml new file mode 100644 index 00000000..35d5c16e --- /dev/null +++ b/.azure-pipelines/windows.yml @@ -0,0 +1,23 @@ +name: Pipenv Build Rules +trigger: + batch: true + branches: + include: + - master + paths: + exclude: + - docs/* + - news/* + - README.md + - pipenv/*.txt + - CHANGELOG.rst + - CONTRIBUTING.md + - CODE_OF_CONDUCT.md + - .gitignore + - .gitattributes + - .editorconfig + +jobs: +- template: jobs/test.yml + parameters: + vmImage: vs2017-win2016 diff --git a/MANIFEST.in b/MANIFEST.in index a8d08c6c..3c8eb1d4 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -28,6 +28,7 @@ recursive-exclude pipenv *.pyi recursive-exclude pipenv *.typed prune peeps +prune .azure-pipelines prune .buildkite prune .github prune .vsts-ci diff --git a/docs/requirements.txt b/docs/requirements.txt index 71c58644..d35a9f32 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -15,7 +15,7 @@ pip-tools==1.9.0 Pygments==2.2.0 pythonz-bd==1.11.4 pytz==2017.2 -requests==2.12.0 +requests==2.20.0 resumable-urlretrieve==0.1.5 semver==2.7.8 six==1.10.0 diff --git a/news/3164.bugfix.rst b/news/3164.bugfix.rst new file mode 100644 index 00000000..7b3fb1ac --- /dev/null +++ b/news/3164.bugfix.rst @@ -0,0 +1 @@ +Azure Pipelines YAML files are updated to use the latest syntax and product name. diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index 74f66d7e..74c57720 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -98,12 +98,12 @@ def cli( warn_in_virtualenv, do_where, project, - spinner, cleanup_virtualenv, ensure_project, format_help, do_clear, ) + from ..utils import create_spinner if man: if system_which("man"): @@ -179,7 +179,7 @@ def cli( ) ) ) - with spinner(): + with create_spinner(text="Running..."): # Remove the virtualenv. cleanup_virtualenv(bare=True) return 0 @@ -312,8 +312,12 @@ def lock( # Ensure that virtualenv is available. ensure_project(three=state.three, python=state.python, pypi_mirror=state.pypi_mirror) if state.installstate.requirementstxt: - do_init(dev=state.installstate.dev, requirements=state.installstate.requirementstxt, - pypi_mirror=state.pypi_mirror, pre=state.installstate.pre) + do_init( + dev=state.installstate.dev, + requirements=state.installstate.requirementstxt, + pypi_mirror=state.pypi_mirror, + pre=state.installstate.pre, + ) do_lock( ctx=ctx, clear=state.clear, @@ -549,8 +553,10 @@ def run_open(state, module, *args, **kwargs): from ..core import which, ensure_project # Ensure that virtualenv is available. - ensure_project(three=state.three, python=state.python, validate=False, - pypi_mirror=state.pypi_mirror) + ensure_project( + three=state.three, python=state.python, + validate=False, pypi_mirror=state.pypi_mirror, + ) c = delegator.run( '{0} -c "import {1}; print({1}.__file__);"'.format(which("python"), module) ) diff --git a/pipenv/cli/options.py b/pipenv/cli/options.py index 99fc5344..c3340bf8 100644 --- a/pipenv/cli/options.py +++ b/pipenv/cli/options.py @@ -3,7 +3,7 @@ from __future__ import absolute_import import os -from click import BOOL as click_booltype +import click.types from click import ( BadParameter, Group, Option, argument, echo, make_pass_decorator, option ) @@ -117,7 +117,7 @@ def sequential_option(f): return value return option("--sequential", is_flag=True, default=False, expose_value=False, help="Install dependencies one-at-a-time, instead of concurrently.", - callback=callback, type=click_booltype)(f) + callback=callback, type=click.types.BOOL)(f) def skip_lock_option(f): @@ -127,7 +127,7 @@ def skip_lock_option(f): return value return option("--skip-lock", is_flag=True, default=False, expose_value=False, help=u"Ignore locking mechanisms when installing—use the Pipfile, instead.", - callback=callback, type=click_booltype)(f) + callback=callback, type=click.types.BOOL)(f) def keep_outdated_option(f): @@ -137,7 +137,7 @@ def keep_outdated_option(f): return value return option("--keep-outdated", is_flag=True, default=False, expose_value=False, help=u"Keep out-dated dependencies from being updated in Pipfile.lock.", - callback=callback, type=click_booltype)(f) + callback=callback, type=click.types.BOOL)(f) def selective_upgrade_option(f): @@ -145,7 +145,7 @@ 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_booltype, + return option("--selective-upgrade", is_flag=True, default=False, type=click.types.BOOL, help="Update specified packages.", callback=callback, expose_value=False)(f) @@ -165,7 +165,7 @@ def dev_option(f): state = ctx.ensure_object(State) state.installstate.dev = value return value - return option("--dev", "-d", is_flag=True, default=False, type=click_booltype, + return option("--dev", "-d", is_flag=True, default=False, type=click.types.BOOL, help="Install both develop and default packages.", callback=callback, expose_value=False)(f) @@ -176,7 +176,7 @@ def pre_option(f): state.installstate.pre = value return value return option("--pre", is_flag=True, default=False, help=u"Allow pre-releases.", - callback=callback, type=click_booltype, expose_value=False)(f) + callback=callback, type=click.types.BOOL, expose_value=False)(f) def package_arg(f): @@ -235,7 +235,7 @@ def site_packages_option(f): state = ctx.ensure_object(State) state.site_packages = value return value - return option("--site-packages", is_flag=True, default=False, type=click_booltype, + return option("--site-packages", is_flag=True, default=False, type=click.types.BOOL, help="Enable site-packages for the virtualenv.", callback=callback, expose_value=False)(f) @@ -245,7 +245,7 @@ def clear_option(f): state = ctx.ensure_object(State) state.clear = value return value - return option("--clear", is_flag=True, callback=callback, type=click_booltype, + return option("--clear", is_flag=True, callback=callback, type=click.types.BOOL, help="Clears caches (pipenv, pip, and pip-tools).", expose_value=False)(f) @@ -257,7 +257,7 @@ def system_option(f): state.system = value return value return option("--system", is_flag=True, default=False, help="System pip management.", - callback=callback, type=click_booltype, expose_value=False)(f) + callback=callback, type=click.types.BOOL, expose_value=False)(f) def requirementstxt_option(f): @@ -295,7 +295,7 @@ 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_booltype, + return option("--deploy", is_flag=True, default=False, type=click.types.BOOL, help=u"Abort if the Pipfile.lock is out-of-date, or Python version is" " wrong.", callback=callback, expose_value=False)(f) diff --git a/pipenv/core.py b/pipenv/core.py index 4cfae2e3..4bd2d10b 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -1,6 +1,5 @@ # -*- coding=utf-8 -*- -import contextlib import logging import os import sys @@ -18,7 +17,6 @@ import warnings import six import urllib3.util as urllib3_util -from functools import partial from .cmdparse import Script from .project import Project, SourceNotFound @@ -42,7 +40,8 @@ from .utils import ( clean_resolved_dep, parse_indexes, escape_cmd, - fix_venv_site + fix_venv_site, + create_spinner, ) from . import environments, pep508checker, progress from .environments import ( @@ -101,26 +100,6 @@ if PIPENV_COLORBLIND: crayons.disable() -@contextlib.contextmanager -def _spinner(text=None, nospin=None, spinner_name=None): - if not text: - text = "Running..." - if not spinner_name: - spinner_name = environments.PIPENV_SPINNER - if nospin is None: - nospin = environments.PIPENV_NOSPIN - with vistir.spin.create_spinner( - spinner_name=spinner_name, - start_text=text, - nospin=nospin - ) as sp: - yield sp - - -spinner = partial(_spinner, text="Running...", nospin=environments.PIPENV_NOSPIN, - spinner_name=environments.PIPENV_SPINNER) - - def which(command, location=None, allow_global=False): if not allow_global and location is None: if project.virtualenv_exists: @@ -300,7 +279,8 @@ def ensure_pipfile(validate=True, skip_requirements=False, system=False): if project.pipfile_is_empty: # Show an error message and exit if system is passed and no pipfile exists if system and not PIPENV_VIRTUALENV: - raise exceptions.PipenvOptionsError("--system", + raise exceptions.PipenvOptionsError( + "--system", "--system is intended to be used for pre-existing Pipfile " "installation, not installation of specific packages. Aborting." ) @@ -314,9 +294,7 @@ def ensure_pipfile(validate=True, skip_requirements=False, system=False): ) # Create a Pipfile… project.create_pipfile(python=python) - with spinner(text=vistir.compat.fs_str("Importing requirements..."), - spinner_name=environments.PIPENV_SPINNER, - nospin=environments.PIPENV_NOSPIN) as sp: + with create_spinner("Importing requirements...") as sp: # Import requirements.txt. try: import_requirements() @@ -466,9 +444,7 @@ def ensure_python(three=None, python=None): crayons.normal(fix_utf8("…"), bold=True), ) ) - with spinner(text=vistir.compat.fs_str("Installing python..."), - spinner_name=environments.PIPENV_SPINNER, - nospin=environments.PIPENV_NOSPIN) as sp: + with create_spinner("Installing python...") as sp: try: c = pyenv.install(version) except PyenvError as e: @@ -762,8 +738,10 @@ def do_install_dependencies( procs = queue.Queue(maxsize=PIPENV_MAX_SUBPROCESS) trusted_hosts = [] - deps_list_bar = progress.bar(deps_list, width=32, - label=INSTALL_LABEL if os.name != "nt" else "") + deps_list_bar = progress.bar( + deps_list, width=32, + label=INSTALL_LABEL if os.name != "nt" else "", + ) indexes = [] for dep in deps_list_bar: index = None @@ -921,9 +899,11 @@ def do_create_virtualenv(python=None, site_packages=False, pypi_mirror=None): # Actually create the virtualenv. nospin = environments.PIPENV_NOSPIN - c = vistir.misc.run(cmd, verbose=False, return_object=True, - spinner_name=environments.PIPENV_SPINNER, combine_stderr=False, - block=False, nospin=nospin, env=pip_config) + c = vistir.misc.run( + cmd, verbose=False, return_object=True, + spinner_name=environments.PIPENV_SPINNER, combine_stderr=False, + block=False, nospin=nospin, env=pip_config, + ) click.echo(crayons.blue("{0}".format(c.out)), err=True) if c.returncode != 0: raise exceptions.VirtualenvCreationException( @@ -1105,17 +1085,18 @@ def do_lock( # Support for --keep-outdated… if keep_outdated: + from pipenv.vendor.packaging.utils import canonicalize_name for section_name, section in ( ("default", project.packages), ("develop", project.dev_packages), ): - for package_specified in section: - norm_name = pep423_name(package_specified) + for package_specified in section.keys(): if not is_pinned(section[package_specified]): - if norm_name in cached_lockfile[section_name]: - lockfile[section_name][norm_name] = cached_lockfile[ + canonical_name = canonicalize_name(package_specified) + if canonical_name in cached_lockfile[section_name]: + lockfile[section_name][canonical_name] = cached_lockfile[ section_name - ][norm_name] + ][canonical_name].copy() # Overwrite any develop packages with default packages. for default_package in lockfile["default"]: if default_package in lockfile["develop"]: @@ -1253,7 +1234,8 @@ def do_init( # Unless we're in a virtualenv not managed by pipenv, abort if we're # using the system's python. if (system or allow_global) and not (PIPENV_VIRTUALENV): - raise exceptions.PipenvOptionsError("--system", + raise exceptions.PipenvOptionsError( + "--system", "--system is intended to be used for Pipfile installation, " "not installation of specific packages. Aborting.\n" "See also: --deploy flag." @@ -1756,9 +1738,11 @@ def do_install( if requirements or package_args or project.pipfile_exists: skip_requirements = True # Don't attempt to install develop and default packages if Pipfile is missing - if not project.pipfile_exists and not packages and dev: - click.echo("Could not find Pipfile.", err=True) - sys.exit(1) + if not project.pipfile_exists and not (packages or dev) and not code: + if not (skip_lock or deploy): + raise exceptions.PipfileNotFound(project.pipfile_location) + elif (skip_lock or deploy) and not project.lockfile_exists: + raise exceptions.LockfileNotFound(project.lockfile_location) concurrent = not sequential # Ensure that virtualenv is available. ensure_project( @@ -1778,15 +1762,7 @@ def do_install( remote = requirements and is_valid_url(requirements) # Warn and exit if --system is used without a pipfile. if (system and package_args) and not (PIPENV_VIRTUALENV): - click.echo( - "{0}: --system is intended to be used for Pipfile installation, " - "not installation of specific packages. Aborting.".format( - crayons.red("Warning", bold=True) - ), - err=True, - ) - click.echo("See also: --deploy flag.", err=True) - sys.exit(1) + raise exceptions.SystemUsageError # Automatically use an activated virtualenv. if PIPENV_USE_SYSTEM: system = True @@ -1923,6 +1899,7 @@ def do_install( pre=pre, requirements_dir=requirements_directory, pypi_mirror=pypi_mirror, + keep_outdated=keep_outdated ) # This is for if the user passed in dependencies, then we want to maek sure we @@ -1940,9 +1917,8 @@ def do_install( ) ) # pip install: - with vistir.contextmanagers.temp_environ(), spinner(text="Installing...", - spinner_name=environments.PIPENV_SPINNER, - nospin=environments.PIPENV_NOSPIN) as sp: + with vistir.contextmanagers.temp_environ(), \ + create_spinner("Installing...") as sp: os.environ["PIP_USER"] = vistir.compat.fs_str("0") try: pkg_requirement = Requirement.from_line(pkg_line) @@ -1952,18 +1928,22 @@ def do_install( sys.exit(1) if index_url: pkg_requirement.index = index_url - c = pip_install( - pkg_requirement, - ignore_hashes=True, - allow_global=system, - selective_upgrade=selective_upgrade, - no_deps=False, - pre=pre, - requirements_dir=requirements_directory, - index=index_url, - extra_indexes=extra_index_url, - pypi_mirror=pypi_mirror, - ) + try: + c = pip_install( + pkg_requirement, + ignore_hashes=True, + allow_global=system, + selective_upgrade=selective_upgrade, + no_deps=False, + pre=pre, + requirements_dir=requirements_directory, + index=index_url, + extra_indexes=extra_index_url, + pypi_mirror=pypi_mirror, + ) + except (ValueError, RuntimeError): + sp.write_err(vistir.compat.fs_str("{0}: {1}".format(crayons.red("WARNING"), e))) + sp.fail(environments.PIPENV_SPINNER_FAIL_TEXT.format("Installation Failed")) # Warn if --editable wasn't passed. if pkg_requirement.is_vcs and not pkg_requirement.editable: sp.write_err( @@ -2040,7 +2020,6 @@ def do_uninstall( ): from .environments import PIPENV_USE_SYSTEM from .vendor.requirementslib.models.requirements import Requirement - from .vendor.requirementslib.models.lockfile import Lockfile from .vendor.packaging.utils import canonicalize_name # Automatically use an activated virtualenv. @@ -2052,8 +2031,10 @@ def do_uninstall( ensure_project(three=three, python=python, pypi_mirror=pypi_mirror) # Un-install all dependencies, if --all was provided. if not any([packages, editable_packages, all_dev, all]): - raise exceptions.MissingParameter(crayons.red("No package provided!"), ctx=ctx, - param_type="parameter") + raise exceptions.MissingParameter( + crayons.red("No package provided!"), + ctx=ctx, param_type="parameter", + ) editable_pkgs = [ Requirement.from_line("-e {0}".format(p)).name for p in editable_packages if p ] @@ -2139,8 +2120,8 @@ def do_uninstall( # Uninstall the package. if package_name in packages_to_remove: cmd = "{0} uninstall {1} -y".format( - escape_grouped_arguments(which_pip(allow_global=system)), package_name - ) + escape_grouped_arguments(which_pip(allow_global=system)), package_name, + ) if environments.is_verbose(): click.echo("$ {0}".format(cmd)) c = delegator.run(cmd) @@ -2203,7 +2184,8 @@ def do_shell(three=None, python=False, fancy=False, shell_args=None, pypi_mirror click.echo(fix_utf8("Launching subshell in virtual environment…"), err=True) fork_args = (project.virtualenv_location, project.project_directory, shell_args) - + with vistir.contextmanagers.temp_environ(): + os.environ.pop("PIP_SHIMS_BASE_MODULE", None) if fancy: shell.fork(*fork_args) return @@ -2337,6 +2319,9 @@ def do_run(command, args, three=None, python=False, pypi_mirror=None): os.environ["PIPENV_ACTIVE"] = vistir.misc.fs_str("1") load_dot_env() # Activate virtualenv under the current interpreter's environment + + with vistir.contextmanagers.temp_environ(): + os.environ.pop("PIP_SHIMS_BASE_MODULE", None) inline_activate_virtual_environment() try: script = project.build_script(command, args) diff --git a/pipenv/exceptions.py b/pipenv/exceptions.py index 95feb859..3fda8021 100644 --- a/pipenv/exceptions.py +++ b/pipenv/exceptions.py @@ -176,6 +176,19 @@ class PipenvOptionsError(PipenvUsageError): self.option_name = option_name +class SystemUsageError(PipenvOptionsError): + def __init__(self, option_name="system", message=None, ctx=None, **kwargs): + extra = kwargs.pop("extra", []) + extra += [ + "{0}: --system is intended to be used for Pipfile installation, " + "not installation of specific packages. Aborting.".format( + crayons.red("Warning", bold=True) + ), + ] + message = crayons.blue("See also: {0}".format(crayons.white("-deploy flag."))) + super(SystemUsageError, self).__init__(option_name, message=message, ctx=ctx, extra=extra, **kwargs) + + class PipfileException(PipenvFileError): def __init__(self, hint=None, **kwargs): from .core import project @@ -239,6 +252,16 @@ class UninstallError(PipenvException): self.extra = extra +class InstallError(PipenvException): + def __init__(self, package, **kwargs): + message = "{0} {1}".format( + crayons.red("ERROR:", bold=True), + crayons.yellow("Package installation failed...") + ) + extra = kwargs.pop("extra", []) + PipenvException.__init__(self, message=fix_utf8(message), extra=extra, **kwargs) + + class CacheError(PipenvException): def __init__(self, path, **kwargs): message = "{0} {1} {2}\n{0}".format( @@ -273,7 +296,7 @@ class ResolutionFailure(PipenvException): crayons.red("ERROR:", bold=True), crayons.yellow(message) ) if no_version_found: - messsage = "{0}\n{1}".format( + message = "{0}\n{1}".format( message, crayons.blue( "Please check your version specifier and version number. " diff --git a/pipenv/utils.py b/pipenv/utils.py index c0d5a356..c9feeafd 100644 --- a/pipenv/utils.py +++ b/pipenv/utils.py @@ -1,16 +1,17 @@ # -*- coding: utf-8 -*- +import contextlib import errno import logging import os import re import shutil +import stat import sys +import warnings import crayons import parse import six -import stat -import warnings from click import echo as click_echo from first import first @@ -363,17 +364,31 @@ class Resolver(object): def populate_file_hashes(self): from pipenv.vendor.vistir.compat import Path, to_native_string from pipenv.vendor.vistir.path import url_to_path + + def _should_include(ireq): + # We can only hash artifacts. + try: + if not ireq.link.is_artifact: + return False + except AttributeError: + return False + + # But we don't want normal pypi artifcats since the normal resolver + # handles those + if is_pypi_url(ireq.link.url): + return False + + # We also don't want to try to hash directories as this will fail + # as these are editable deps and are not hashable. + if (ireq.link.scheme == "file" and + Path(to_native_string(url_to_path(ireq.link.url))).is_dir()): + return False + return True + self.hashes.update({ ireq: self.resolver._hash_cache.get_hash(ireq.link) - for ireq in self.parsed_constraints if (getattr(ireq, "link", None) - # We can only hash artifacts, but we don't want normal pypi artifcats since the - # normal resolver handles those - and ireq.link.is_artifact and not (is_pypi_url(ireq.link.url) or ( - # We also don't want to try to hash directories as this will fail - # as these are editable deps and are not hashable - ireq.link.scheme == "file" and - Path(to_native_string(url_to_path(ireq.link.url))).is_dir() - ))) + for ireq in self.parsed_constraints + if _should_include(ireq) }) @property @@ -428,8 +443,9 @@ def actually_resolve_deps( if not req_dir: req_dir = create_tracked_tempdir(suffix="-requirements", prefix="pipenv-") - constraints = get_resolver_metadata(deps, index_lookup, markers_lookup, project, - sources) + constraints = get_resolver_metadata( + deps, index_lookup, markers_lookup, project, sources, + ) resolver = Resolver(constraints, req_dir, project, sources, clear=clear, pre=pre) resolved_tree = resolver.resolve() hashes = resolver.resolve_hashes() @@ -437,6 +453,21 @@ def actually_resolve_deps( return (resolved_tree, hashes, markers_lookup, resolver) +@contextlib.contextmanager +def create_spinner(text, nospin=None, spinner_name=None): + import vistir.spin + if not spinner_name: + spinner_name = environments.PIPENV_SPINNER + if nospin is None: + nospin = environments.PIPENV_NOSPIN + with vistir.spin.create_spinner( + spinner_name=spinner_name, + start_text=vistir.compat.fs_str(text), + nospin=nospin + ) as sp: + yield sp + + def venv_resolve_deps( deps, which, @@ -450,7 +481,6 @@ def venv_resolve_deps( from .vendor.vistir.compat import Path, to_native_string, JSONDecodeError from .vendor.vistir.path import create_tracked_tempdir from .cmdparse import Script - from .core import spinner from .vendor.pexpect.exceptions import EOF, TIMEOUT from .vendor import delegator from . import resolver @@ -481,8 +511,7 @@ def venv_resolve_deps( os.environ["PIP_NO_INPUT"] = fs_str("1") out = to_native_string("") EOF.__module__ = "pexpect.exceptions" - with spinner(text=fs_str("Locking..."), spinner_name=environments.PIPENV_SPINNER, - nospin=environments.PIPENV_NOSPIN) as sp: + with create_spinner(text=fs_str("Locking...")) as sp: c = delegator.run(Script.parse(cmd).cmdify(), block=False, env=os.environ.copy()) _out = decode_output("") result = None @@ -1221,8 +1250,6 @@ def get_vcs_deps( dev=False, pypi_mirror=None, ): - from .vendor.vistir.compat import Path - from .vendor.vistir.path import create_tracked_tempdir from .vendor.requirementslib.models.requirements import Requirement section = "vcs_dev_packages" if dev else "vcs_packages" @@ -1280,8 +1307,10 @@ def translate_markers(pipfile_entry): marker_set.add(str(Marker("{0}{1}".format(m, entry)))) new_pipfile.pop(m) if marker_set: - new_pipfile["markers"] = str(Marker(" or ".join(["{0}".format(s) if " and " in s else s - for s in sorted(dedup(marker_set))]))).replace('"', "'") + new_pipfile["markers"] = str(Marker(" or ".join( + "{0}".format(s) if " and " in s else s + for s in sorted(dedup(marker_set)) + ))).replace('"', "'") return new_pipfile @@ -1289,9 +1318,6 @@ def clean_resolved_dep(dep, is_top_level=False, pipfile_entry=None): name = pep423_name(dep["name"]) # We use this to determine if there are any markers on top level packages # So we can make sure those win out during resolution if the packages reoccur - dep_keys = ( - [k for k in getattr(pipfile_entry, "keys", list)()] if is_top_level else [] - ) lockfile = {"version": "=={0}".format(dep["version"])} for key in ["hashes", "index", "extras"]: if key in dep: @@ -1406,10 +1432,14 @@ def looks_like_dir(path): def parse_indexes(line): from argparse import ArgumentParser parser = ArgumentParser("indexes") - parser.add_argument("--index", "-i", "--index-url", metavar="index_url", - action="store", nargs="?",) - parser.add_argument("--extra-index-url", "--extra-index", metavar="extra_indexes", - action="append") + parser.add_argument( + "--index", "-i", "--index-url", + metavar="index_url", action="store", nargs="?", + ) + parser.add_argument( + "--extra-index-url", "--extra-index", + metavar="extra_indexes",action="append", + ) parser.add_argument("--trusted-host", metavar="trusted_hosts", action="append") args, remainder = parser.parse_known_args(line.split()) index = [] if not args.index else [args.index,] diff --git a/pipenv/vendor/pythonfinder/environment.py b/pipenv/vendor/pythonfinder/environment.py index 7c69b9fc..27a5b3fc 100644 --- a/pipenv/vendor/pythonfinder/environment.py +++ b/pipenv/vendor/pythonfinder/environment.py @@ -7,7 +7,9 @@ import sys PYENV_INSTALLED = bool(os.environ.get("PYENV_SHELL")) or bool( os.environ.get("PYENV_ROOT") ) -PYENV_ROOT = os.path.expandvars(os.environ.get("PYENV_ROOT", "~/.pyenv")) +PYENV_ROOT = os.path.expanduser( + os.path.expandvars(os.environ.get("PYENV_ROOT", "~/.pyenv")) +) IS_64BIT_OS = None SYSTEM_ARCH = platform.architecture()[0] diff --git a/pipenv/vendor/pythonfinder/models/pyenv.py b/pipenv/vendor/pythonfinder/models/pyenv.py index 5874af64..4a8dfc65 100644 --- a/pipenv/vendor/pythonfinder/models/pyenv.py +++ b/pipenv/vendor/pythonfinder/models/pyenv.py @@ -71,7 +71,7 @@ class PyenvFinder(BaseFinder, BasePath): @versions.default def get_versions(self): versions = defaultdict() - bin_ = sysconfig._INSTALL_SCHEMES[sysconfig._get_default_scheme()]["scripts"] + bin_ = sysconfig._INSTALL_SCHEMES['posix_prefix']["scripts"] for p in self.get_version_order(): bin_dir = Path(bin_.format(base=p.as_posix())) version_path = None diff --git a/pipenv/vendor/vistir/__init__.py b/pipenv/vendor/vistir/__init__.py index c8a995fa..f3554d56 100644 --- a/pipenv/vendor/vistir/__init__.py +++ b/pipenv/vendor/vistir/__init__.py @@ -31,7 +31,7 @@ from .path import mkdir_p, rmtree, create_tracked_tempdir, create_tracked_tempfi from .spin import VistirSpinner, create_spinner -__version__ = "0.2.3" +__version__ = "0.2.4" __all__ = [ diff --git a/pipenv/vendor/vistir/path.py b/pipenv/vendor/vistir/path.py index ba008159..b1236884 100644 --- a/pipenv/vendor/vistir/path.py +++ b/pipenv/vendor/vistir/path.py @@ -8,7 +8,6 @@ import os import posixpath import shutil import stat -import sys import warnings import six @@ -206,9 +205,8 @@ def mkdir_p(newdir, mode=0o777): target = os.path.join(head, tail) if os.path.exists(target) and os.path.isfile(target): raise OSError( - "A file with the same name as the desired dir, '{0}', already exists.".format( - to_text(newdir, encoding="utf-8") - ) + "A file with the same name as the desired dir, '{0}', " + "already exists.".format(to_text(newdir, encoding="utf-8")) ) os.makedirs(os.path.join(head, tail), mode) diff --git a/pipenv/vendor/vistir/spin.py b/pipenv/vendor/vistir/spin.py index 20587d9d..f8c4e009 100644 --- a/pipenv/vendor/vistir/spin.py +++ b/pipenv/vendor/vistir/spin.py @@ -153,11 +153,15 @@ class VistirSpinner(base_obj): def ok(self, text="OK"): """Set Ok (success) finalizer to a spinner.""" + self._text = None + _text = text if text else "OK" self._freeze(_text) def fail(self, text="FAIL"): """Set fail finalizer to a spinner.""" + self._text = None + _text = text if text else "FAIL" self._freeze(_text) diff --git a/tests/pytest-pypi/Pipfile b/tests/pytest-pypi/Pipfile deleted file mode 100644 index 6abe710c..00000000 --- a/tests/pytest-pypi/Pipfile +++ /dev/null @@ -1,23 +0,0 @@ -[[source]] - -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - - -[packages] - - - -[dev-packages] - -pytest = "*" -"e1839a8" = {path = ".", editable = true} -httpbin = "*" -requests = "*" -twine = "*" - - -[requires] - -python_version = "3.6" diff --git a/tests/pytest-pypi/Pipfile.lock b/tests/pytest-pypi/Pipfile.lock deleted file mode 100644 index 25978b9d..00000000 --- a/tests/pytest-pypi/Pipfile.lock +++ /dev/null @@ -1,480 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "b871e70f9f0b7bd3852672c371c754d8db50e5015c8dbdad1d217a3e58a26c33" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.6" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": {}, - "develop": { - "argparse": { - "hashes": [ - "sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4", - "sha256:c31647edb69fd3d465a847ea3157d37bed1f95f19760b11a47aa91c04b666314" - ], - "markers": "python_version == '2.6'", - "version": "==1.4.0" - }, - "attrs": { - "hashes": [ - "sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9", - "sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450" - ], - "version": "==17.4.0" - }, - "blinker": { - "hashes": [ - "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6" - ], - "version": "==1.4" - }, - "brotlipy": { - "hashes": [ - "sha256:07194f4768eb62a4f4ea76b6d0df6ade185e24ebd85877c351daa0a069f1111a", - "sha256:091b299bf36dd6ef7a06570dbc98c0f80a504a56c5b797f31934d2ad01ae7d17", - "sha256:09ec3e125d16749b31c74f021aba809541b3564e5359f8c265cbae442810b41a", - "sha256:0be698678a114addcf87a4b9496c552c68a2c99bf93cf8e08f5738b392e82057", - "sha256:0fa6088a9a87645d43d7e21e32b4a6bf8f7c3939015a50158c10972aa7f425b7", - "sha256:1ea4e578241504b58f2456a6c69952c88866c794648bdc74baee74839da61d44", - "sha256:2699945a0a992c04fc7dc7fa2f1d0575a2c8b4b769f2874a08e8eae46bef36ae", - "sha256:2a80319ae13ea8dd60ecdc4f5ccf6da3ae64787765923256b62c598c5bba4121", - "sha256:2e5c64522364a9ebcdf47c5744a5ddeb3f934742d31e61ebfbbc095460b47162", - "sha256:36def0b859beaf21910157b4c33eb3b06d8ce459c942102f16988cca6ea164df", - "sha256:3a3e56ced8b15fbbd363380344f70f3b438e0fd1fcf27b7526b6172ea950e867", - "sha256:3c1d5e2cf945a46975bdb11a19257fa057b67591eb232f393d260e7246d9e571", - "sha256:50ca336374131cfad20612f26cc43c637ac0bfd2be3361495e99270883b52962", - "sha256:5de6f7d010b7558f72f4b061a07395c5c3fd57f0285c5af7f126a677b976a868", - "sha256:637847560d671657f993313ecc6c6c6666a936b7a925779fd044065c7bc035b9", - "sha256:653faef61241bf8bf99d73ca7ec4baa63401ba7b2a2aa88958394869379d67c7", - "sha256:786afc8c9bd67de8d31f46e408a3386331e126829114e4db034f91eacb05396d", - "sha256:79aaf217072840f3e9a3b641cccc51f7fc23037496bd71e26211856b93f4b4cb", - "sha256:7e31f7adcc5851ca06134705fcf3478210da45d35ad75ec181e1ce9ce345bb38", - "sha256:8b39abc3256c978f575df5cd7893153277216474f303e26f0e43ba3d3969ef96", - "sha256:9448227b0df082e574c45c983fa5cd4bda7bfb11ea6b59def0940c1647be0c3c", - "sha256:96bc59ff9b5b5552843dc67999486a220e07a0522dddd3935da05dc194fa485c", - "sha256:a07647886e24e2fb2d68ca8bf3ada398eb56fd8eac46c733d4d95c64d17f743b", - "sha256:af65d2699cb9f13b26ec3ba09e75e80d31ff422c03675fcb36ee4dabe588fdc2", - "sha256:b4c98b0d2c9c7020a524ca5bbff42027db1004c6571f8bc7b747f2b843128e7a", - "sha256:c6cc0036b1304dd0073eec416cb2f6b9e37ac8296afd9e481cac3b1f07f9db25", - "sha256:d2c1c724c4ac375feb2110f1af98ecdc0e5a8ea79d068efb5891f621a5b235cb", - "sha256:dc6c5ee0df9732a44d08edab32f8a616b769cc5a4155a12d2d010d248eb3fb07", - "sha256:fd1d1c64214af5d90014d82cee5d8141b13d44c92ada7a0c0ec0679c6f15a471" - ], - "version": "==0.7.0" - }, - "certifi": { - "hashes": [ - "sha256:14131608ad2fd56836d33a71ee60fa1c82bc9d2c8d98b7bdbc631fe1b3cd1296", - "sha256:edbc3f203427eef571f79a7692bb160a2b0f7ccaa31953e99bd17e307cf63f7d" - ], - "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" - ], - "version": "==1.11.5" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" - }, - "click": { - "hashes": [ - "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d", - "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b" - ], - "version": "==6.7" - }, - "colorama": { - "hashes": [ - "sha256:463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda", - "sha256:48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1" - ], - "markers": "sys_platform == 'win32'", - "version": "==0.3.9" - }, - "contextlib2": { - "hashes": [ - "sha256:509f9419ee91cdd00ba34443217d5ca51f5a364a404e1dce9e8979cea969ca48", - "sha256:f5260a6e679d2ff42ec91ec5252f4eeffdcf21053db9113bd0a8e4d953769c00" - ], - "markers": "python_version < '3.2'", - "version": "==0.5.5" - }, - "crayons": { - "hashes": [ - "sha256:5e17691605e564d63482067eb6327d01a584bbaf870beffd4456a3391bd8809d", - "sha256:6f51241d0c4faec1c04c1c0ac6a68f1d66a4655476ce1570b3f37e5166a599cc" - ], - "version": "==0.1.2" - }, - "dateparser": { - "hashes": [ - "sha256:940828183c937bcec530753211b70f673c0a9aab831e43273489b310538dff86", - "sha256:b452ef8b36cd78ae86a50721794bc674aa3994e19b570f7ba92810f4e0a2ae03" - ], - "version": "==0.7.0" - }, - "decorator": { - "hashes": [ - "sha256:7d46dd9f3ea1cf5f06ee0e4e1277ae618cf48dfb10ada7c8427cd46c42702a0e", - "sha256:94d1d8905f5010d74bbbd86c30471255661a14187c45f8d7f3e5aa8540fdb2e5" - ], - "version": "==4.2.1" - }, - "e1839a8": { - "editable": true, - "path": "." - }, - "flask": { - "hashes": [ - "sha256:0749df235e3ff61ac108f69ac178c9770caeaccad2509cb762ce1f65570a8856", - "sha256:49f44461237b69ecd901cc7ce66feea0319b9158743dd27a2899962ab214dac1" - ], - "version": "==0.12.2" - }, - "flask-cache": { - "hashes": [ - "sha256:33187b3ddceeee233fe3db68ffcc118b5498e8ad28edde711bcbdcbf4924ce35", - "sha256:90126ca9bc063854ef8ee276e95d38b2b4ec8e45fd77d5751d37971ee27c7ef4", - "sha256:ae9d1ac4549517dfbc1f178ccc5429f61f836be3cc109a0b2481c98b3711c329" - ], - "version": "==0.13.1" - }, - "flask-common": { - "hashes": [ - "sha256:44fbb57a12bc7478d56c223eb5de7b2fb98ce42a70314c74ffecf5dbe75ed1b8" - ], - "version": "==0.2.0" - }, - "flask-limiter": { - "hashes": [ - "sha256:473aa5bc97310406aa8c12ab3dc080697bcfa8cd21a6d0aba30916911bbc673c", - "sha256:8cce98dcf25bf2ddbb824c2b503b4fc8e1a139154240fd2c60d9306bad8a0db8" - ], - "version": "==1.0.1" - }, - "funcsigs": { - "hashes": [ - "sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca", - "sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50" - ], - "markers": "python_version < '3.0'", - "version": "==1.0.2" - }, - "greenlet": { - "hashes": [ - "sha256:09ef2636ea35782364c830f07127d6c7a70542b178268714a9a9ba16318e7e8b", - "sha256:0fef83d43bf87a5196c91e73cb9772f945a4caaff91242766c5916d1dd1381e4", - "sha256:1b7df09c6598f5cfb40f843ade14ed1eb40596e75cd79b6fa2efc750ba01bb01", - "sha256:1fff21a2da5f9e03ddc5bd99131a6b8edf3d7f9d6bc29ba21784323d17806ed7", - "sha256:42118bf608e0288e35304b449a2d87e2ba77d1e373e8aa221ccdea073de026fa", - "sha256:50643fd6d54fd919f9a0a577c5f7b71f5d21f0959ab48767bd4bb73ae0839500", - "sha256:58798b5d30054bb4f6cf0f712f08e6092df23a718b69000786634a265e8911a9", - "sha256:5b49b3049697aeae17ef7bf21267e69972d9e04917658b4e788986ea5cc518e8", - "sha256:75c413551a436b462d5929255b6dc9c0c3c2b25cbeaee5271a56c7fda8ca49c0", - "sha256:769b740aeebd584cd59232be84fdcaf6270b8adc356596cdea5b2152c82caaac", - "sha256:ad2383d39f13534f3ca5c48fe1fc0975676846dc39c2cece78c0f1f9891418e0", - "sha256:b417bb7ff680d43e7bd7a13e2e08956fa6acb11fd432f74c97b7664f8bdb6ec1", - "sha256:b6ef0cabaf5a6ecb5ac122e689d25ba12433a90c7b067b12e5f28bdb7fb78254", - "sha256:c2de19c88bdb0366c976cc125dca1002ec1b346989d59524178adfd395e62421", - "sha256:c7b04a6dc74087b1598de8d713198de4718fa30ec6cbb84959b26426c198e041", - "sha256:f8f2a0ae8de0b49c7b5b2daca4f150fdd9c1173e854df2cce3b04123244f9f45", - "sha256:fcfadaf4bf68a27e5dc2f42cbb2f4b4ceea9f05d1d0b8f7787e640bed2801634" - ], - "version": "==0.4.13" - }, - "gunicorn": { - "hashes": [ - "sha256:75af03c99389535f218cc596c7de74df4763803f7b63eb09d77e92b3956b36c6", - "sha256:eee1169f0ca667be05db3351a0960765620dad53f53434262ff8901b68a1b622" - ], - "version": "==19.7.1" - }, - "httpbin": { - "hashes": [ - "sha256:0afa0486a76305cac441b5cc80d5d4ccd82b20875da7c5119ecfe616cefef45f", - "sha256:7c3a4d69f9d495e6df1d51a50ba7b1e4f33a1cb61e0db95ee7f8953e27a2243f" - ], - "version": "==0.6.2" - }, - "humanize": { - "hashes": [ - "sha256:a43f57115831ac7c70de098e6ac46ac13be00d69abbf60bdcac251344785bb19" - ], - "version": "==0.5.1" - }, - "idna": { - "hashes": [ - "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f", - "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4" - ], - "version": "==2.6" - }, - "itsdangerous": { - "hashes": [ - "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" - ], - "version": "==0.24" - }, - "jinja2": { - "hashes": [ - "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", - "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" - ], - "version": "==2.10" - }, - "limits": { - "hashes": [ - "sha256:9df578f4161017d79f5188609f1d65f6b639f8aad2914c3960c9252e56a0ff95", - "sha256:a017b8d9e9da6761f4574642149c337f8f540d4edfe573fb91ad2c4001a2bc76" - ], - "version": "==1.3" - }, - "markupsafe": { - "hashes": [ - "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" - ], - "version": "==1.0" - }, - "maya": { - "hashes": [ - "sha256:ad1969bae78afb148c45a2f63591a7575ec05b4a0ab7ec04987ab7d73649f9d6", - "sha256:d8a7ed8513b2990036fe456c9f595b54d19ec49cb4461cd95a2ef6c487fb55eb" - ], - "version": "==0.3.4" - }, - "meinheld": { - "hashes": [ - "sha256:293eff4983b7fcbd9134b47706b22189883fe354993bd10163c65869d141e565", - "sha256:40d9dbce0165b2d9142f364d26fd6d59d3682f89d0dfe2117717a8ddad1f4133" - ], - "version": "==0.6.1" - }, - "pendulum": { - "hashes": [ - "sha256:0c14388546db6605a860b8b7112cb69d0b11c9ce5e072210504544e0d4575799", - "sha256:39a255776528afe11ea0d57814f9bf3729c1e0b99063af2e5c6cfd750c3e1f7f", - "sha256:3c85e8cbc91f45e1cc916cc9180b34153cd6aaaaacfb51a48b3156318314fa82", - "sha256:8199206c479b13947dcac63c025575d035331bb3819d1783dc1d568a11962906", - "sha256:8798aeca58b3dd7ffdc5a4993c9eaafedc4048165429e8f499ddd62c73bf3964", - "sha256:881efe37328de0785c0731d462e1485a45712f2cd5cb55907d6c15458460ebeb", - "sha256:bcca072f82e84b419efec1320cd3ee5c230d263f3a601b146651ed4db77d89f0", - "sha256:ff0c5fa3af4a471a218408c448b804ac6bccb105127727474f4e83c0e4072e97" - ], - "version": "==1.4.2" - }, - "pkginfo": { - "hashes": [ - "sha256:31a49103180ae1518b65d3f4ce09c784e2bc54e338197668b4fb7dc539521024", - "sha256:bb1a6aeabfc898f5df124e7e00303a5b3ec9a489535f346bfbddb081af93f89e" - ], - "version": "==1.4.1" - }, - "pluggy": { - "hashes": [ - "sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff" - ], - "version": "==0.6.0" - }, - "py": { - "hashes": [ - "sha256:8cca5c229d225f8c1e3085be4fcf306090b00850fefad892f9d96c7b6e2f310f", - "sha256:ca18943e28235417756316bfada6cd96b23ce60dd532642690dcfdaba988a76d" - ], - "version": "==1.5.2" - }, - "pycparser": { - "hashes": [ - "sha256:99a8ca03e29851d96616ad0404b4aad7d9ee16f25c9f9708a11faf2810f7b226" - ], - "version": "==2.18" - }, - "pytest": { - "hashes": [ - "sha256:8970e25181e15ab14ae895599a0a0e0ade7d1f1c4c8ca1072ce16f25526a184d", - "sha256:9ddcb879c8cc859d2540204b5399011f842e5e8823674bf429f70ada281b3cc6" - ], - "version": "==3.4.1" - }, - "python-dateutil": { - "hashes": [ - "sha256:891c38b2a02f5bb1be3e4793866c8df49c7d19baabf9c1bad62547e0b4866aca", - "sha256:95511bae634d69bc7329ba55e646499a842bc4ec342ad54a8cdb65645a0aad3c" - ], - "version": "==2.6.1" - }, - "pytz": { - "hashes": [ - "sha256:07edfc3d4d2705a20a6e99d97f0c4b61c800b8232dc1c04d87e8554f130148dd", - "sha256:3a47ff71597f821cd84a162e71593004286e5be07a340fd462f0d33a760782b5", - "sha256:410bcd1d6409026fbaa65d9ed33bf6dd8b1e94a499e32168acfc7b332e4095c0", - "sha256:5bd55c744e6feaa4d599a6cbd8228b4f8f9ba96de2c38d56f08e534b3c9edf0d", - "sha256:61242a9abc626379574a166dc0e96a66cd7c3b27fc10868003fa210be4bff1c9", - "sha256:887ab5e5b32e4d0c86efddd3d055c1f363cbaa583beb8da5e22d2fa2f64d51ef", - "sha256:ba18e6a243b3625513d85239b3e49055a2f0318466e0b8a92b8fb8ca7ccdf55f", - "sha256:ed6509d9af298b7995d69a440e2822288f2eca1681b8cce37673dbb10091e5fe", - "sha256:f93ddcdd6342f94cea379c73cddb5724e0d6d0a1c91c9bdef364dc0368ba4fda" - ], - "version": "==2018.3" - }, - "pytzdata": { - "hashes": [ - "sha256:4e2cceb54335cd6c28caea46b15cd592e2aec5e8b05b0241cbccfb1b23c02ae7", - "sha256:7cd949123e2c2060fd12793de3a4a449e36b5dea5e169b810a3ac3f0b9877cfa" - ], - "version": "==2018.3" - }, - "raven": { - "hashes": [ - "sha256:738a52019d01955d5b44b49d67c9f2f4cedb1b4f70d4fb0b493931174d00e044", - "sha256:92bf4c4819472ed20f1b9905eeeafe1bc6fe5f273d7c14506fdb8fb3a6ab2074" - ], - "version": "==6.6.0" - }, - "regex": { - "hashes": [ - "sha256:1b428a296531ea1642a7da48562746309c5c06471a97bd0c02dd6a82e9cecee8", - "sha256:27d72bb42dffb32516c28d218bb054ce128afd3e18464f30837166346758af67", - "sha256:32cf4743debee9ea12d3626ee21eae83052763740e04086304e7a74778bf58c9", - "sha256:32f6408dbca35040bc65f9f4ae1444d5546411fde989cb71443a182dd643305e", - "sha256:333687d9a44738c486735955993f83bd22061a416c48f5a5f9e765e90cf1b0c9", - "sha256:35eeccf17af3b017a54d754e160af597036435c58eceae60f1dd1364ae1250c7", - "sha256:361a1fd703a35580a4714ec28d85e29780081a4c399a99bbfb2aee695d72aedb", - "sha256:494bed6396a20d3aa6376bdf2d3fbb1005b8f4339558d8ac7b53256755f80303", - "sha256:5b9c0ddd5b4afa08c9074170a2ea9b34ea296e32aeea522faaaaeeeb2fe0af2e", - "sha256:a50532f61b23d4ab9d216a6214f359dd05c911c1a1ad20986b6738a782926c1a", - "sha256:a9243d7b359b72c681a2c32eaa7ace8d346b7e8ce09d172a683acf6853161d9c", - "sha256:b44624a38d07d3c954c84ad302c29f7930f4bf01443beef5589e9157b14e2a29", - "sha256:be42a601aaaeb7a317f818490a39d153952a97c40c6e9beeb2a1103616405348", - "sha256:eee4d94b1a626490fc8170ffd788883f8c641b576e11ba9b4a29c9f6623371e0", - "sha256:f69d1201a4750f763971ea8364ed95ee888fc128968b39d38883a72a4d005895" - ], - "version": "==2018.2.21" - }, - "requests": { - "hashes": [ - "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", - "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" - ], - "version": "==2.18.4" - }, - "requests-toolbelt": { - "hashes": [ - "sha256:42c9c170abc2cacb78b8ab23ac957945c7716249206f90874651971a4acff237", - "sha256:f6a531936c6fa4c6cfce1b9c10d5c4f498d16528d2a54a22ca00011205a187b5" - ], - "version": "==0.8.0" - }, - "ruamel.yaml": { - "hashes": [ - "sha256:01e30ecb1b1c0ebf9fce814dc20dace402571517277799291202b61b22096c24", - "sha256:02babffd019911841ba01b76e23dfec7c9e9b2725503fb2698c4982fa1a6e835", - "sha256:072f6364a89972e8dc0afdce3335a709d5464dfeaa4f736d092a54574338b874", - "sha256:14d161558e3bf89e87d77c218098be22fa9a0d6d0bea40250fce525b1d0cbee2", - "sha256:5504398fc755a2b14c9983b2101161a8591a4b30812590cc1c365e7fcc117dfa", - "sha256:68c8f2986bcb91b6db1aea8698941769840c7257e951a9377048f7eff35be773", - "sha256:6d05c5a5baf829c70916c226ef3200650846a7227de226bca8a59efaf88bb973", - "sha256:6d7929b24e329d662fa43b657fddfee5260e2d35d0a543065cd755d4e17a9b2f", - "sha256:8dc74821e4bb6b21fb1ab35964e159391d99ee44981d07d57bf96e2395f3ef75", - "sha256:9225c83952d28f302cfc23c3d9a6f8231bfd581476d7aff1e3c7de49eecb4ee9", - "sha256:b6c5d5f03ba78e3f27c7188a00c4e09b6a4507fe3154ba40a294e09cb30ee016", - "sha256:c0908896e34b617ead40552cab03c1769bdc43d1da02419160dc900c5dfddde2", - "sha256:c41e04b526d0153c9246cfab87d7ddefdc9f165cb8886a8ec48ba7a2b73069f6", - "sha256:e2d2715bf92156bec5fb42e92e95dac1c4d9904f8a3d4e2d0c438758fe9092d7", - "sha256:e3bbfe0d294e08fdbb0cb05485435a2ceb4e168e98b5dc611f051c1864986b4b", - "sha256:f2d02a4af5a13b09d0b823cdd0317b54f3e0115e50b5ac4d9840c3a1b566817f", - "sha256:fcfc24a21594c071cc4588e84b7657a1f47ebcf6037c6c43fa15c4bbd3989ec2" - ], - "version": "==0.15.35" - }, - "six": { - "hashes": [ - "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", - "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" - ], - "version": "==1.11.0" - }, - "tqdm": { - "hashes": [ - "sha256:5ec0d4442358e55cdb4a0471d04c6c831518fd8837f259db5537d90feab380df", - "sha256:f66468c14ccd011a627734c9b3fd72f20ce16f8faecc47384eb2507af5924fb9" - ], - "version": "==4.19.6" - }, - "twine": { - "hashes": [ - "sha256:caa45b7987fc96321258cd7668e3be2ff34064f5c66d2d975b641adca659c1ab", - "sha256:d3ce5c480c22ccfb761cd358526e862b32546d2fe4bc93d46b5cf04ea3cc46ca" - ], - "version": "==1.9.1" - }, - "tzlocal": { - "hashes": [ - "sha256:4ebeb848845ac898da6519b9b31879cf13b6626f7184c496037b818e238f2c4e" - ], - "version": "==1.5.1" - }, - "urllib3": { - "hashes": [ - "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", - "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" - ], - "version": "==1.22" - }, - "werkzeug": { - "hashes": [ - "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c", - "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b" - ], - "version": "==0.14.1" - }, - "whitenoise": { - "hashes": [ - "sha256:15f43b2e701821b95c9016cf469d29e2a546cb1c7dead584ba82c36f843995cf", - "sha256:9d81515f2b5b27051910996e1e860b1332e354d9e7bcf30c98f21dcb6713e0dd" - ], - "version": "==3.3.1" - } - } -}