This is a pre-production deployment of Warehouse. Changes made here affect the production instance of PyPI (
Help us improve Python packaging - Donate today!

Validating URI References per RFC 3986

Project Description

A Python implementation of RFC 3986 including validation and authority parsing.


Use pip to install rfc3986 like so:

pip install rfc3986

Example Usage

The following are the two most common use cases envisioned for rfc3986.

Replacing urlparse

To parse a URI and receive something very similar to the standard library’s urllib.parse.urlparse

from rfc3986 import urlparse

ssh = urlparse('ssh://')
print(ssh.scheme)  # => ssh
print(ssh.userinfo)  # => user
print(ssh.params)  # => None
print(ssh.port)  # => 29418

To create a copy of it with new pieces you can use copy_with:

new_ssh = ssh.copy_with(
print(new_ssh.scheme)  # => https
print(new_ssh.userinfo)  # => None
# etc.

Strictly Parsing a URI and Applying Validation

To parse a URI into a convenient named tuple, you can simply:

from rfc3986 import uri_reference

example = uri_reference('')
email = uri_reference('')
ssh = uri_reference('ssh://')

With a parsed URI you can access data about the components:

print(example.scheme)  # => http
print(email.path)  # =>
print(ssh.userinfo)  # => user
print(  # =>
print(ssh.port)  # => 29418

It can also parse URIs with unicode present:

uni = uri_reference(b'\xe2\x98\x83')  # ☃
print(uni.query)  # utf8=%E2%98%83

With a parsed URI you can also validate it:

if ssh.is_valid():['git', 'clone', ssh.unsplit()])

You can also take a parsed URI and normalize it:

mangled = uri_reference('hTTp://exAMPLe.COM')
print(mangled.scheme)  # => hTTp
print(mangled.authority)  # => exAMPLe.COM

normal = mangled.normalize()
print(normal.scheme)  # => http
print(mangled.authority)  # =>

But these two URIs are (functionally) equivalent:

if normal == mangled:

Your paths, queries, and fragments are safe with us though:

mangled = uri_reference('hTTp://exAMPLe.COM/Some/reallY/biZZare/pAth')
normal = mangled.normalize()
assert normal == 'hTTp://exAMPLe.COM/Some/reallY/biZZare/pAth'
assert normal == ''
assert normal != ''

If you do not actually need a real reference object and just want to normalize your URI:

from rfc3986 import normalize_uri

assert (normalize_uri('hTTp://exAMPLe.COM/Some/reallY/biZZare/pAth') ==

You can also very simply validate a URI:

from rfc3986 import is_valid_uri

assert is_valid_uri('hTTp://exAMPLe.COM/Some/reallY/biZZare/pAth')

Requiring Components

You can validate that a particular string is a valid URI and require independent components:

from rfc3986 import is_valid_uri

assert is_valid_uri('http://localhost:8774/v2/resource',

# Assert that a mailto URI is invalid if you require an authority
# component
assert is_valid_uri('', require_authority=True) is False

If you have an instance of a URIReference, you can pass the same arguments to URIReference#is_valid, e.g.,

from rfc3986 import uri_reference

http = uri_reference('http://localhost:8774/v2/resource')
assert uri.is_valid(require_scheme=True,

# Assert that a mailto URI is invalid if you require an authority
# component
mailto = uri_reference('')
assert uri.is_valid(require_authority=True) is False


  • rfc3987

    This is a direct competitor to this library, with extra features, licensed under the GPL.

  • uritools

    This can parse URIs in the manner of RFC 3986 but provides no validation and only recently added Python 3 support.

  • Standard library’s urlparse/urllib.parse

    The functions in these libraries can only split a URI (valid or not) and provide no validation.


This project follows and enforces the Python Software Foundation’s Code of Conduct.

If you would like to contribute but do not have a bug or feature in mind, feel free to email Ian and find out how you can help.

The git repository for this project is maintained at

Release History

Release History

This version
History Node


History Node


History Node


History Node


History Node


History Node


History Node


History Node


History Node


History Node


History Node


Download Files

Download Files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

File Name & Checksum SHA256 Checksum Help Version File Type Upload Date
rfc3986-1.1.0-py2.py3-none-any.whl (29.1 kB) Copy SHA256 Checksum SHA256 py2.py3 Wheel Jul 18, 2017
rfc3986-1.1.0.tar.gz (39.4 kB) Copy SHA256 Checksum SHA256 Source Jul 18, 2017

Supported By

WebFaction WebFaction Technical Writing Elastic Elastic Search Pingdom Pingdom Monitoring Dyn Dyn DNS Sentry Sentry Error Logging CloudAMQP CloudAMQP RabbitMQ Heroku Heroku PaaS Kabu Creative Kabu Creative UX & Design Fastly Fastly CDN DigiCert DigiCert EV Certificate Rackspace Rackspace Cloud Servers DreamHost DreamHost Log Hosting