From eb0243865079c7c2179730da93130447556ea020 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 25 Nov 2017 21:33:34 +0100 Subject: [PATCH] Better handling of file URLs This allows for using `file:///absolute/path`, which was previously prevented due to the missing `netloc`. This allows for all file URLs that `urlunparse` turns back into the original URL to be valid. --- CHANGELOG.rst | 8 ++++++++ packaging/requirements.py | 5 ++++- tests/test_requirements.py | 12 ++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 33ece45a..d5919c14 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,14 @@ Changelog * Fix string representation of PEP 508 direct URL requirements with markers. +* Better handling of file URLs + + This allows for using ``file:///absolute/path``, which was previously + prevented due to the missing ``netloc``. + + This allows for all file URLs that ``urlunparse`` turns back into the + original URL to be valid. + 18.0 - 2018-09-26 ~~~~~~~~~~~~~~~~~ diff --git a/packaging/requirements.py b/packaging/requirements.py index e20d90a1..68b01adf 100644 --- a/packaging/requirements.py +++ b/packaging/requirements.py @@ -99,7 +99,10 @@ def __init__(self, requirement_string): self.name = req.name if req.url: parsed_url = urlparse.urlparse(req.url) - if not (parsed_url.scheme and parsed_url.netloc) or ( + if parsed_url.scheme == 'file': + if urlparse.urlunparse(parsed_url) != req.url: + raise InvalidRequirement("Invalid URL given") + elif not (parsed_url.scheme and parsed_url.netloc) or ( not parsed_url.scheme and not parsed_url.netloc): raise InvalidRequirement("Invalid URL: {0}".format(req.url)) self.url = req.url diff --git a/tests/test_requirements.py b/tests/test_requirements.py index f1212949..f1a43fda 100644 --- a/tests/test_requirements.py +++ b/tests/test_requirements.py @@ -107,6 +107,18 @@ def test_invalid_url(self): assert "Invalid URL: " in str(e) assert "gopher:/foo/com" in str(e) + def test_file_url(self): + req = Requirement("name @ file:///absolute/path") + self._assert_requirement(req, "name", "file:///absolute/path") + req = Requirement("name @ file://.") + self._assert_requirement(req, "name", "file://.") + + def test_invalid_file_urls(self): + with pytest.raises(InvalidRequirement): + Requirement("name @ file:.") + with pytest.raises(InvalidRequirement): + Requirement("name @ file:/.") + def test_extras_and_url_and_marker(self): req = Requirement( "name [fred,bar] @ http://foo.com ; python_version=='2.7'")