diff --git a/README.md b/README.md index 740f11d5..c3a46889 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,11 @@ Pipenv: Python Development Workflow for Humans **Pipenv** is a tool that aims to bring the best of all packaging worlds (bundler, composer, npm, cargo, yarn, etc.) to the Python world. -*Windows is a first--class citizen, in our world.* +*Windows is a first-class citizen, in our world.* It automatically creates and manages a virtualenv for your projects, as well as adds/removes packages from your `Pipfile` as you -install/uninstall packages. It also generates the ever--important +install/uninstall packages. It also generates the ever-important `Pipfile.lock`, which is used to produce deterministic builds. ![image](http://media.kennethreitz.com.s3.amazonaws.com/pipenv.gif) diff --git a/news/2373.bugfix.rst b/news/2373.bugfix.rst new file mode 100644 index 00000000..9b42add1 --- /dev/null +++ b/news/2373.bugfix.rst @@ -0,0 +1 @@ +Raise `PipenvUsageError` when [[source]] does not contain url field. diff --git a/news/3427.bugfix.rst b/news/3427.bugfix.rst new file mode 100644 index 00000000..42f659f0 --- /dev/null +++ b/news/3427.bugfix.rst @@ -0,0 +1 @@ +Fix a bug that ``ValidationError`` is thrown when some fields are missing in source section. diff --git a/news/3446.trivial.rst b/news/3446.trivial.rst new file mode 100644 index 00000000..1eb98bbb --- /dev/null +++ b/news/3446.trivial.rst @@ -0,0 +1 @@ +Fix the wrong order of old and new hashes in message. diff --git a/peeps/PEEP-003.md b/peeps/PEEP-003.md new file mode 100644 index 00000000..d0493eaa --- /dev/null +++ b/peeps/PEEP-003.md @@ -0,0 +1,9 @@ +# PEEP-003: Revocation of Power of BDFL + +**ACCEPTED** + +Pipenv will be governed by a board of maintainers (trusted collaborators to the project on GitHub), not a BDFL. + +The BDFL retains his title, however, revokes himself of his powers. + +PEEP approval will be determined by available members of the board of maintainers, in private or public channels. diff --git a/pipenv/core.py b/pipenv/core.py index 9c1971d5..934f13b6 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -1186,9 +1186,9 @@ def do_init( ) else: if old_hash: - msg = fix_utf8("Pipfile.lock ({1}) out of date, updating to ({0})…") + msg = fix_utf8("Pipfile.lock ({0}) out of date, updating to ({1})…") else: - msg = fix_utf8("Pipfile.lock is corrupted, replaced with ({0})…") + msg = fix_utf8("Pipfile.lock is corrupted, replaced with ({1})…") click.echo( crayons.red(msg.format(old_hash[-6:], new_hash[-6:]), bold=True), err=True, @@ -2498,7 +2498,7 @@ def do_graph(bare=False, json=False, json_tree=False, reverse=False): if not project.virtualenv_exists: click.echo( u"{0}: No virtualenv has been created for this project yet! Consider " - u"running {1} first to automatically generate one for you or see" + u"running {1} first to automatically generate one for you or see " u"{2} for further instructions.".format( crayons.red("Warning", bold=True), crayons.green("`pipenv install`"), diff --git a/pipenv/project.py b/pipenv/project.py index e8550a04..edbcff87 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -780,7 +780,7 @@ class Project(object): return { "hash": {"sha256": self.calculate_pipfile_hash()}, "pipfile-spec": PIPFILE_SPEC_CURRENT, - "sources": sources, + "sources": [self.populate_source(s) for s in sources], "requires": self.parsed_pipfile.get("requires", {}) } diff --git a/pipenv/utils.py b/pipenv/utils.py index 08847e59..5ed21264 100644 --- a/pipenv/utils.py +++ b/pipenv/utils.py @@ -31,6 +31,7 @@ import crayons import parse from . import environments +from .exceptions import PipenvUsageError from .pep508checker import lookup @@ -203,20 +204,26 @@ def prepare_pip_source_args(sources, pip_args=None): pip_args = [] if sources: # Add the source to notpip. - pip_args.extend(["-i", sources[0]["url"]]) + package_url = sources[0].get("url") + if not package_url: + raise PipenvUsageError("[[source]] section does not contain a URL.") + pip_args.extend(["-i", package_url]) # Trust the host if it's not verified. if not sources[0].get("verify_ssl", True): pip_args.extend( - ["--trusted-host", urllib3_util.parse_url(sources[0]["url"]).host] + ["--trusted-host", urllib3_util.parse_url(package_url).host] ) # Add additional sources as extra indexes. if len(sources) > 1: for source in sources[1:]: - pip_args.extend(["--extra-index-url", source["url"]]) + url = source.get("url") + if not url: # not harmless, just don't continue + continue + pip_args.extend(["--extra-index-url", url]) # Trust the host if it's not verified. if not source.get("verify_ssl", True): pip_args.extend( - ["--trusted-host", urllib3_util.parse_url(source["url"]).host] + ["--trusted-host", urllib3_util.parse_url(url).host] ) return pip_args diff --git a/setup.py b/setup.py index 6583cff1..4c848c47 100644 --- a/setup.py +++ b/setup.py @@ -27,10 +27,7 @@ required = [ "setuptools>=36.2.1", "virtualenv-clone>=0.2.5", "virtualenv", - 'requests[security];python_version<"2.7"', - 'ordereddict;python_version<"2.7"', - 'enum34; python_version<"3"', - 'typing; python_version<"3.5"' + 'enum34; python_version<"3"' ] diff --git a/tests/integration/test_lock.py b/tests/integration/test_lock.py index ab5178a0..75095ac0 100644 --- a/tests/integration/test_lock.py +++ b/tests/integration/test_lock.py @@ -491,6 +491,7 @@ def test_lockfile_with_empty_dict(PipenvInstance): @pytest.mark.lock +@pytest.mark.skip_lock @pytest.mark.install def test_lock_with_incomplete_source(PipenvInstance, pypi): with PipenvInstance(pypi=pypi, chdir=True) as p: @@ -502,6 +503,8 @@ url = "https://test.pypi.org/simple" [packages] requests = "*" """) + c = p.pipenv('install --skip-lock') + assert c.return_code == 0 c = p.pipenv('install') assert c.return_code == 0 assert p.lockfile['_meta']['sources'] diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index aeaf3ed3..ac5eb29b 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -8,6 +8,7 @@ from mock import Mock, patch import pipenv.utils import pythonfinder.utils +from pipenv.exceptions import PipenvUsageError # Pipfile format <-> requirements.txt format. @@ -374,6 +375,11 @@ twine = "*" == expected_args ) + def test_invalid_prepare_pip_source_args(self): + sources = [{}] + with pytest.raises(PipenvUsageError): + pipenv.utils.prepare_pip_source_args(sources, pip_args=None) + @pytest.mark.utils def test_parse_python_version(self): ver = pipenv.utils.parse_python_version("Python 3.6.5\n")