{"id":13339958,"url":"https://github.com/marrow/uri","last_synced_at":"2025-04-30T05:33:55.839Z","repository":{"id":62586609,"uuid":"93084120","full_name":"marrow/uri","owner":"marrow","description":"A type to represent, query, and manipulate a Uniform Resource Identifier.","archived":false,"fork":false,"pushed_at":"2024-01-25T09:04:56.000Z","size":277,"stargazers_count":20,"open_issues_count":10,"forks_count":6,"subscribers_count":3,"default_branch":"develop","last_synced_at":"2024-10-25T09:55:42.209Z","etag":null,"topics":["python","uri","uri-components","uri-fragments","uri-manipulations","uri-normalize","uri-parser","uri-path","uri-query","uri-template","uri-templates","url","url-builder","url-encoder","url-parameters","url-parser","url-parsing"],"latest_commit_sha":null,"homepage":"https://pretty-rfc.herokuapp.com/RFC3986","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marrow.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-06-01T17:47:16.000Z","updated_at":"2024-09-29T05:56:55.000Z","dependencies_parsed_at":"2024-06-19T01:39:36.418Z","dependency_job_id":"397f8de8-d685-44a6-92fe-2630fc7a7a09","html_url":"https://github.com/marrow/uri","commit_stats":{"total_commits":121,"total_committers":1,"mean_commits":121.0,"dds":0.0,"last_synced_commit":"74960dd59c64e8ffcb864e5b742b2495340711e1"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marrow%2Furi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marrow%2Furi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marrow%2Furi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marrow%2Furi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marrow","download_url":"https://codeload.github.com/marrow/uri/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224200415,"owners_count":17272437,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["python","uri","uri-components","uri-fragments","uri-manipulations","uri-normalize","uri-parser","uri-path","uri-query","uri-template","uri-templates","url","url-builder","url-encoder","url-parameters","url-parser","url-parsing"],"created_at":"2024-07-29T19:21:23.109Z","updated_at":"2024-11-12T01:24:34.139Z","avatar_url":"https://github.com/marrow.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"===\nuri\n===\n\n    © 2017-2023 Alice Bevan-McGregor and contributors.\n\n..\n\n    https://github.com/marrow/uri\n\n..\n\n    |latestversion| |ghtag| |downloads| |masterstatus| |mastercover| |masterreq| |ghwatch| |ghstar|\n\n\nInstallation\n============\n\nInstalling ``uri`` is easy, just execute the following in a terminal::\n\n    pip install uri\n\n**Note:** We *strongly* recommend always using a container, virtualization, or sandboxing environment of some kind when\ndeveloping using Python; installing things system-wide is yucky (for a variety of reasons) nine times out of ten.  We\nprefer light-weight `virtualenv \u003chttps://virtualenv.pypa.io/en/latest/virtualenv.html\u003e`__, others prefer solutions as\nrobust as `Vagrant \u003chttp://www.vagrantup.com\u003e`__.\n\nIf you add ``uri`` to the ``install_requires`` argument of the call to ``setup()`` in your application's\n``setup.py`` file, ``uri`` will be automatically installed and made available when your own application or\nlibrary is installed.  We recommend using \"less than\" version numbers to ensure there are no unintentional\nside-effects when updating.  Use ``uri\u003c2.1`` to get all bug fixes for the current release, and\n``uri\u003c3.0`` to get bug fixes and feature updates while ensuring that large breaking changes are not installed.\n\nWhile ``uri`` does not have any hard dependencies on any other package, it is **strongly** recommended that\napplications using ``uri`` in web-based applications also install the\n`MarkupSafe \u003chttps://pypi.org/project/MarkupSafe/\u003e`__ package to provide more efficient string escaping and some\nadditional functionality.\n\n\nDevelopment Version\n-------------------\n\n    |developstatus| |developcover| |ghsince| |issuecount| |ghfork|\n\nDevelopment takes place on `GitHub \u003chttps://github.com/\u003e`__ in the `uri\n\u003chttps://github.com/marrow/uri/\u003e`__ project.  Issue tracking, documentation, downloads, and test automation\nare provided there.\n\nInstalling the current development version requires `Git \u003chttps://git-scm.com/\u003e`__, a distributed source code\nmanagement system.  If you have Git you can run the following to download and *link* the development version into your\nPython runtime::\n\n    git clone https://github.com/marrow/uri.git\n    (cd uri; python setup.py develop)\n\nYou can then upgrade to the latest version at any time::\n\n    (cd uri; git pull; python setup.py develop)\n\nIf you would like to make changes and contribute them back to the project, fork the GitHub project, make your changes,\nand submit a pull request.  This process is beyond the scope of this documentation; for more information see\n`GitHub's documentation \u003chttp://help.github.com/\u003e`_.\n\n\nGetting Started\n===============\n\n\nURI\n---\n\nAn abstract string-like (and mapping-like, and iterator-like...) identifier for a resource with the regular form\ndefined by `RFC 3986 \u003chttp://pretty-rfc.herokuapp.com/RFC3986\u003e`_::\n\n    scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]\n\nFor details on these components, `please refer to Wikipedia\n\u003chttps://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax\u003e`__. Each of these components is represented by an\nappropriate rich datatype:\n\n* The ``scheme`` of a URI represents an extensible API of string-like plugins.\n* Any IPv6 ``host`` is automatically wrapped and unwrapped in square braces.\n* The ``path`` is represented by a ``PurePosixPath``.\n* The ``query`` is a rich ordered multi-value bucketed mutable mapping called ``QSO``. (Ouch, but that's what it is!)\n\nInstantiate a new URI by passing in a string or string-castable object, ``pathlib.Path`` compatible object, or object\nexposing a ``__link__`` method or attribute::\n\n    home = URI(\"https://github.com/marrow/\")\n\nThe *scalar* attributes are combined into several *compound* groups for convenience:\n\n* The ``credentials`` are a colon (``:``) separated combination of: ``user`` + ``password`` — also accessible via the\n  shorter ``auth`` or the longer ``authentication`` attributes. May be assigned using array/mapping notation.\n  Accessing ``uri[user:pass]`` will return a mutated instance with credentials included.\n* The ``authority`` part is the combination of: ``credentials`` + ``host`` + ``port``\n* The ``heirarchical`` part is the combination of: ``authority`` part + ``path``\n\nOther aliases are provided for the scalar components, typically for compliance with external APIs, such as\ninteroperability with ``pathlib.Path`` or ``urlsplit`` objects:\n\n* ``username`` is the long form of ``user``.\n* ``hostname`` is the long form of ``host``.\n* ``authentication`` is the long form of ``auth``.\n\nIn addition, several string views are provided for convenience, but ultimately all just call `str()` against the\ninstance or one of the compound groups described above:\n\n* ``uri`` represents the entire URI as a string.\n* ``safe_uri`` represents the entire URI, sans any password that may be present.\n* ``base`` is the combination of ``scheme`` and the ``heirarchical`` part.\n* ``summary`` is a useful shortcut for web presentation containing only the ``host`` and ``port`` of the URI.\n* ``qs`` is just the query string, as a plain string instead of QSO instance.\n\nURI values may be absolute identifiers or relative references. Absolute URIs are what most people see every day:\n\n* ``https://example.com/about/us``\n* ``ftp://example.com/thing.txt``\n* ``mailto:user@example.com``\n* ``uri:ISSN:1535-3613``\n\nIndirect references require the context of an absolute identifier in order to resolve them. Examples include:\n\n* ``//example.com/protocol/relative`` — protocol implied from context, frequently used in HTML when referencing\n  resources hosted on content delivery networks.\n* ``/host/relative`` — all elements *up to* the path are preserved from context, also frequently used in HTML when\n  referencing resources on the same server. This is not equivalent to ``file:///host/relative``, as the protocol is\n  unknown.\n* ``relative/path`` — the resulting path is relative to the \"current working directory\" of the context.\n* ``../parent/relative/path`` — references may ascend into parents of the context.\n* ``resource#fragment`` — referencing a specific fragment of a sibling resource.\n* ``#fragment`` — a same-document reference to a specific fragment of the context.\n\nTwo primary methods are provided to combine a base URI with another URI, absolute or relative.  The first, utilizing\nthe ``uri.resolve(uri, **parts)`` method, allows you to both resolve a target URL as well as provide explicit\noverrides for any of the above scalar attributes, such as query string. The second, which is recommended for general\nuse, is to use the division and floor division operators::\n\n    base = URI(\"https://example.com/about/us\")\n    cdn = base // \"cdn.example.com\"\n    js = cdn / \"script.js\"\n    css = cdn / \"script.css\"\n\nPlease note that once a URI has an \"authority\" part (basically, the parts prior to the path such as host) then any\npath directly assigned must be \"rooted\", or contain a leading slash.\n\n\nSchemes\n-------\n\nEach URI has a scheme that should be registered with the `Internet Assigned Numbers Authority (IANA)\n\u003chttps://en.m.wikipedia.org/wiki/Internet_Assigned_Numbers_Authority\u003e`_ and specifies the mechanics of the URI\nfields. Examples include: ``http``, ``https``, ``ftp``, ``mailto``, ``file``, ``data``, etc.\n\nThe declaration of which schemes are URL-like (featuring a `://` double-slashed separator) is based on Python's\n``entry_points`` plugin registry mapping scheme names to the ``Scheme`` objects used to handle them. If a scheme\nrenders URI-like when your application requires URL-like, you can `utilize package metadata\n\u003chttps://packaging.python.org/guides/creating-and-discovering-plugins/#using-package-metadata\u003e`_ to register\nadditional mappings.\n\nFor an example, and to see the core set handled this way, examine the ``setup.py`` and ``setup.cfg`` files within this\nproject. If you wish to imperatively define schemes, you can do so with code such as the following. It is **strongly\nrecommended** to not implement this as an *import time side effect*. To mutate the plugin registry directly::\n\n    from uri.scheme import URLScheme\n    from uri.part.scheme import SchemePart\n    \n    SchemePart.registry['amqp'] = URLScheme('amqp')\n    SchemePart.registry['amqps'] = URLScheme('amqps')\n\nSubsequent attempts to resolve ``entry_points`` by these names will now resolve to the objects you have specified.\n\n\nWSGI\n----\n\nA WSGI request environment contains all of the details required to reconstruct the requested URI. The simplest example\nof why one might do this is to form a \"base URI\" for relative resolution. WSGI environment-wrapping objects such as\n`WebOb's \u003chttps://webob.org\u003e`_ ``Request`` class instances may be used as long as the object passed in exposes the\noriginal WSGI environment using an attribute named ``environ``.\n\nTo perform this task, use the ``URI.from_wsgi`` factory method::\n\n    from webob import Request\n\n    request = Request.blank('https://example.com/foo/bar?baz=27')\n    uri = URI.from_wsgi(request)\n    assert str(uri) == 'https://example.com/foo/bar?baz=27'\n\n\nMigrating\n=========\n\nA vast majority of other URI parsers emit plain dictionaries or provide ``as_dict`` methods. URI objects can be\ntransformed into such using a fairly basic \"dictionary comprehension\"::\n\n    uri = URI('http://www.example.com/3.0/dd/ff/')\n    {i: getattr(uri, i) for i in dir(uri) if i[0] != '_' and not callable(getattr(uri, i))}\n\nThe above will produce a dictionary of all URI attributes that are not \"private\" (prefixed by an underscore) or\nexecutable methods.\n\n\nFrom ``furl``\n-------------\n\n    https://github.com/gruns/furl\n\n* A majority of the object attributes have parity: ``scheme``, ``username``, ``password``, ``host``, even ``origin``.\n* ``furl.args`` -\u003e ``URI.query``\n* ``furl.add()``, ``furl.set()``, ``furl.remove()`` -\u003e inline, chained manipulation is not supported.\n* ``furl.url`` -\u003e ``str(uri)`` or ``URI.uri``\n* ``furl.netloc`` -\u003e ``URI.authority``\n* Fragments do not have ``path`` and ``query`` attributes; under ``URI`` the fragment is a pure string.\n* ``furl.path`` -\u003e ``URI.path`` where ``furl`` implements its own, ``URI.path`` are PurePosixPath instances.\n* ``furl.join`` is accomplished via division operators under ``URI``, or for more complete relative resolution, use\n  the ``URI.resolve`` method.\n* The ``URI`` class does not currently infer protocol-specific default port numbers.\n* Manipulation via division operators preserves query string parameters under ``furl``, however the ``URI`` package\n  assumes relative URL resolution, which updates the path and clears parameters and fragment. To extend the path while\n  preserving these::\n  \n      uri = URI('http://www.google.com/base?one=1\u0026two=2')\n      uri.path /= 'path'\n      assert str(uri) == 'http://www.google.com/base/path?one=1\u0026two=2'\n\n\nFrom ``dj-mongohq-url``\n-----------------------\n\n    https://github.com/ferrix/dj-mongohq-url\n\nWhere your ``settings.py`` file's ``DATABASES`` declaration used ``dj_mongohq_url.config``, instead use::\n\n    from uri.parse.db import parse_dburi\n    \n    DATABASES = {'default': parse_dburi('mongodb://...')}\n\n\nFrom ``django-url-tools``\n-------------------------\n\n    https://bitbucket.org/monwara/django-url-tools\n\nThe majority of the ``UrlHelper`` attributes are directly applicable to ``URI`` instances, occasionally with minor\ndifferences, typically of naming. The differences are documented here, and \"template tags\" and \"filters\" are not\nprovided for.\n\n* Where ``UrlHelper.path`` are plain strings, ``URI.path`` attributes are `PurePosixPath\n  \u003chttps://docs.python.org/3/library/pathlib.html#pure-paths\u003e_` instances which support typecasting to a string if\n  needed.\n\n* ``UrlHelper.query_dict`` and ``UrlHelper.query`` are replaced with the dict-like ``URI.query`` attribute.\n\n* ``UrlHelper.query_string`` is shortened to ``URI.qs``, additionally, the object retrieved when accessing ``query``\n  may be cast to a string as per the rich path representation.\n\n* ``UrlHelper.get_full_path`` -- equivalent to the ``URI.resource`` compound, combining path, query string, and\n  fragment identifier.\n\n* ``UrlHelper.get_full_quoted_path`` -- alternative currently not provided.\n\n* There are no direct equivalents provided for:\n\n  * ``UrlHelper.hash`` -- **not** provided due to FIPS-unsafe dependence on MD5.\n  * ``UrlHelper.get_query_string`` -- encoding is handled automatically.\n  * ``UrlHelper.get_query_data`` -- this helper for subclass inheritance is not provided.\n  * ``UrlHelper.update_query_data`` -- manipulate the query directly using ``URI.query.update``.\n  * ``UrlHelper.overload_params`` -- can be accomplished using modern dictionary merge literal syntax.\n  * ``UrlHelper.toggle_params`` -- this seems an unusual use case, and can be resolved similarly to the last.\n  * ``UrlHelper.get_path`` -- unnecessary, access ``URI.path`` directly.\n  * ``UrlHelper.del_param`` and ``UrlHelper.del_params`` -- just utilize the ``del`` keyword (or ``pop`` method) on/of\n    the ``URI.query`` attribute.\n\n\nFrom ``url2vapi``\n-----------------\n\n    https://github.com/Drachenfels/url2vapi\n\nWhere ``url2vapi`` provides a dictionary of parsed URL components, with some pattern-based extraction of API metadata,\n``URI`` provides a rich object with descriptor attributes. Version parsing can be accomplished by extracting the\nrelevant path element and parsing it::\n\n    from pkg_resources import parse_version\n    from uri import URI\n    \n    url = 'http://www.example.com/3.0/dd/ff/'\n    uri = URI(url)\n    version = parse_version(uri.path.parts[1])\n\nThe ``ApiUrl`` class otherwise offers no functionality. The minimal \"data model\" provided only accounts for:\n\n* ``protocol`` -\u003e ``scheme``\n* ``port`` is common, though URI port numbers are stored as integers, not strings.\n* ``domain`` -\u003e ``host``\n* ``remainder`` does not have an equivalent; there are several compound getters which may provide similar results.\n* ``kwargs`` also has no particular equivalent. URI instances are not \"arbitrarily extensible\".\n* Parsing of URL \"parameters\" incorrectly assume these are exclusive to the referenced resource, as per query string\n  arguments, when each path element may have its own distinct parameters. The difference between::\n  \n      https://example.com/foo/bar/baz?prop=27\n      https://example.com/foo/bar/baz;prop=27\n  \n  And::\n  \n      https://example.com/foo;prop=27/bar/baz;prop=27\n      https://example.com/foo/bar;prop=27/baz\n      https://example.com/foo/bar/baz;prop=27\n\n\nFrom ``url-parser``\n-------------------\n\n    https://github.com/AdaptedAS/url_parser\n\n* ``protocol`` -\u003e ``scheme``\n* ``www`` has no equivalent; check for ``URI.host.startswith('www.')`` instead.\n* ``sub_domain`` has no equivalent; parse/split ``URI.host`` instead.\n* ``domain`` -\u003e ``host``\n* ``top_domain`` has no equivalent; as per ``sub_domain``.\n* ``dir`` -\u003e ``path``\n* ``file`` -\u003e ``path``\n* ``fragment`` is unchanged.\n* ``query`` -\u003e ``qs`` for the string form, ``query`` for a rich ``QSO`` instance interface.\n\n\nFrom ``p.url``\n--------------\n\n    https://github.com/ultrabluewolf/p.url/\n\nThere may be a noticeable trend arising from several sections of \"migrating from\". Many seem to have accessor or\nmanipulation **methods** to mutate the object, rather than utilizing native data type interactions, this one does not\nbuck the trend. Additionally, many of the \"attributes\" of ``Purl`` are provided as invokable getter/setter methods,\nnot as static attributes nor automatic properties. In this comparison, attributes trailed by parenthesis are actually\nmethods, if ``[value]`` may be passed, the method is also the setter. Lastly, it provides its own ``InvalidUrlError``\nwhich does not subclass ``ValueError``.\n\nThe result is a bit of a hodgepodge API that feels more at home in Java.\n\n* ``Purl.query`` is a plain dictionary attribute, not a getter method. Now a rich dict-like ``QSO`` object.\n* ``Purl.querystring()`` -\u003e ``URI.qs`` -- pure getter method in ``Purl``.\n* ``Purl.add_query()`` and ``Purl.delete_query()`` -- just manipulate ``URI.query`` as a dictionary.\n* An alternative to ``param`` for manipulation of path parameters is not provided, as these are protocol-defined.\n* ``Purl.protocol([value])`` -\u003e ``URI.scheme``\n* ``Purl.hostname([value])`` -\u003e ``URI.host``\n* ``Purl.port([value])`` -\u003e ``URI.port``\n* ``Purl.path([value])`` -\u003e ``URI.path``\n* \"Parameter expansion\" (which is unrelated to actual URI path element parameters) is not currently supported;\n  recommended to simply use f-strings or ``str.format`` as appropriate. As curly braces have no special meaning to\n  ``URI``, you may populate these within one for later ``str(uri).format(...)`` interpolation.\n\n\nFrom ``url``\n------------\n\n    https://github.com/seomoz/url-py\n\nThe ``url`` package bundles Cython auto-generated C++ extensions. I do not understand why.\n\nIt's nearly 16,000 lines of code.\n\nSixteen thousand.\n\nA number of attributes are common such as ``scheme``, ``host``, ``hostname``, ``port``, etc.\n\n* ``URL.pld`` and ``URL.tld`` are left as an exercise for the reader.\n* ``URL.params`` is not currently implemented.\n* ``URL.query`` -\u003e ``URI.qs`` with ``URI.query`` providing a rich dict-like interface.\n* ``URL.unicode`` and ``URL.utf8`` are unimplemented. Native ``URI`` storage is Unicode, it's up to you to encode.\n* ``URL.strip()`` is unnecessary under ``URI``; empty query strings, fragments, etc., naturally will not have\n  dividers. What many might consider to be an \"invalid\" query string often are not; an encoding for HTTP key-value\n  pairs is suggested for the HTTP scheme, however everything after the ``?`` is just a single string, up to server-\n  side interpretation. ``?????a=1`` is \"perfectly fine\".\n* Re-ordering of query string parameters is not implemented; the need is dubious at this level.\n* ``URL.deparam()`` may be implemented by using `del` to remove known query string arguments, or using the ``pop()``\n  method to safely remove arguments that may only be conditionally present, while avoiding exceptions.\n* ``URL.abspath()`` is not currently implemented; to be implemented within ``URI.resolve()``.\n* ``URL.unescape()`` is not currently implemented.\n* ``URL.relative()`` may be implemented more succinctly using division operators, e.g. ``base / target``. This also\n  supports HTTP reference protocol-relative resolution using the floor division operator, e.g. ``base // target``.\n* ``URL.punycode()`` and ``URL.unpunycode()`` are not implemented, as the goal is for Unicode to be natively/naturally\n  supported with Punycode encoding automatic at instantiation and serialization to string time, reference `#18\n  \u003chttps://github.com/marrow/uri/issues/18\u003e`_.\n\n\n\nVersion History\n===============\n\nVersion 3.0.0\n-------------\n\n* Improved documentation, notably, incorporated the imperative registration of schemes example from `#14\n  \u003chttps://github.com/marrow/uri/issues/14#issuecomment-667567337\u003e`_.\n* Inclusion of adaption utilities and tests obviating the need for other utility packages, and documented migration\n  from several other URI or URL implementations.\n* Removed legacy Python 2 support adaptions.\n* Removed Python 3 support less than Python 3.8 due to type annotation functionality and syntax changes.\n* Broad adoption of type hinting annotations across virtually all methods and instance attributes.\n* Updated ABC import path references to correct Python 3.9 warnings.\n* Added syntax sugar for assignment of URI authentication credentials by returning a mutated instance when sliced. `#10\n  \u003chttps://github.com/marrow/uri/issues/10\u003e`_\n* Additional ``__slots__`` declarations to improve memory efficiency.\n* Added RFC example relative resolutions as tests; we are a compatible resolver, not a strict one.\n* Added ability to construct a URI from a populated WSGI request environment to reconstruct the requested URI. WebOb\n  added as a testing dependency to cover this feature. `#13 \u003chttps://github.com/marrow/uri/issues/13\u003e`_\n* Migrated from Travis-CI to GitHub Actions for test runner automation.\n* Added a significant number of additional pre-registered URL-like (``://``) schemes, based on Wikipedia references.\n* Automatically utilize Punycode / IDNA encoding of internationalized domain names, ones containing non-ASCII. `#18\n  \u003chttps://github.com/marrow/uri/issues/18\u003e`_\n\n\nVersion 2.0.1\n-------------\n\n* Added non-standard `resource` compound view.\n* Removed Python 3.3 support, added 3.7, removed deprecated testing dependency.\n* Scheme objects hash as per their string representation. `#5 \u003chttps://github.com/marrow/uri/issues/5\u003e`_\n* Dead code clean-up.\n* Additional tests covering previously uncovered edge cases, such as assignment to a compound view property.\n* Restrict assignment of rootless paths (no leading `/`) if an authority part is already present. `#8\n  \u003chttps://github.com/marrow/uri/issues/8\u003e`_\n* Enable handling of the following schemes as per URL (colon + double slash):\n\t* sftp\n\t* mysql\n\t* redis\n\t* mongodb\n\n\nVersion 2.0\n-----------\n\n* Extraction of the ``URIString`` object from Marrow Mongo.\n\n\nVersion 1.0\n-----------\n\n* Original package by Jacob Kaplan-Moss. Copyright 2008 and released under the BSD License.\n\n\nLicense\n=======\n\nThe URI package has been released under the MIT Open Source license.\n\nThe MIT License\n---------------\n\nCopyright © 2017-2023 Alice Bevan-McGregor and contributors.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\ndocumentation files (the “Software”), to deal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit\npersons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the\nSoftware.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\nWARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n.. |ghwatch| image:: https://img.shields.io/github/watchers/marrow/uri.svg?style=social\u0026label=Watch\n    :target: https://github.com/marrow/uri/subscription\n    :alt: Subscribe to project activity on Github.\n\n.. |ghstar| image:: https://img.shields.io/github/stars/marrow/uri.svg?style=social\u0026label=Star\n    :target: https://github.com/marrow/uri/subscription\n    :alt: Star this project on Github.\n\n.. |ghfork| image:: https://img.shields.io/github/forks/marrow/uri.svg?style=social\u0026label=Fork\n    :target: https://github.com/marrow/uri/fork\n    :alt: Fork this project on Github.\n\n.. |masterstatus| image:: http://img.shields.io/travis/marrow/uri/master.svg?style=flat\n    :target: https://travis-ci.org/marrow/uri/branches\n    :alt: Release build status.\n\n.. |mastercover| image:: http://img.shields.io/codecov/c/github/marrow/uri/master.svg?style=flat\n    :target: https://codecov.io/github/marrow/uri?branch=master\n    :alt: Release test coverage.\n\n.. |masterreq| image:: https://img.shields.io/requires/github/marrow/uri.svg\n    :target: https://requires.io/github/marrow/uri/requirements/?branch=master\n    :alt: Status of release dependencies.\n\n.. |developstatus| image:: http://img.shields.io/travis/marrow/uri/develop.svg?style=flat\n    :target: https://travis-ci.org/marrow/uri/branches\n    :alt: Development build status.\n\n.. |developcover| image:: http://img.shields.io/codecov/c/github/marrow/uri/develop.svg?style=flat\n    :target: https://codecov.io/github/marrow/uri?branch=develop\n    :alt: Development test coverage.\n\n.. |developreq| image:: https://img.shields.io/requires/github/marrow/uri.svg\n    :target: https://requires.io/github/marrow/uri/requirements/?branch=develop\n    :alt: Status of development dependencies.\n\n.. |issuecount| image:: http://img.shields.io/github/issues-raw/marrow/uri.svg?style=flat\n    :target: https://github.com/marrow/uri/issues\n    :alt: Github Issues\n\n.. |ghsince| image:: https://img.shields.io/github/commits-since/marrow/uri/2.0.0.svg\n    :target: https://github.com/marrow/uri/commits/develop\n    :alt: Changes since last release.\n\n.. |ghtag| image:: https://img.shields.io/github/tag/marrow/uri.svg\n    :target: https://github.com/marrow/uri/tree/2.0.0\n    :alt: Latest Github tagged release.\n\n.. |latestversion| image:: http://img.shields.io/pypi/v/uri.svg?style=flat\n    :target: https://pypi.python.org/pypi/uri\n    :alt: Latest released version.\n\n.. |downloads| image:: http://img.shields.io/pypi/dw/uri.svg?style=flat\n    :target: https://pypi.python.org/pypi/uri\n    :alt: Downloads per week.\n\n.. |cake| image:: http://img.shields.io/badge/cake-lie-1b87fb.svg?style=flat\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarrow%2Furi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarrow%2Furi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarrow%2Furi/lists"}