Source code for plaster.uri
from collections import OrderedDict
import os.path
from urllib import parse
from .exceptions import InvalidURI
[docs]
class PlasterURL:
"""
Represents the components of a URL used to locate a
:class:`plaster.ILoader`.
:ivar scheme: The name of the loader backend.
:ivar path: The loader-specific path string.
This is the entirety of the ``config_uri`` passed to
:func:`plaster.parse_uri` without the scheme, fragment and options.
If this value is falsey it is replaced with an empty string.
:ivar options: A dictionary of options parsed from the query string as
url-encoded key=value pairs.
:ivar fragment: A loader-specific default section name.
This parameter may be used by loaders in scenarios where they provide
APIs that support a default name. For example, a loader that provides
``get_wsgi_app`` may use the fragment to determine the name of the
section containing the WSGI app if none was explicitly defined.
If this value is falsey it is replaced with an empty string.
"""
def __init__(self, scheme, path="", options=None, fragment=""):
self.scheme = scheme
if not path:
path = ""
self.path = path
if options is None:
options = {}
self.options = options
if not fragment:
fragment = ""
self.fragment = fragment
def __str__(self):
result = "{0.scheme}://{0.path}".format(self)
if self.options:
result += "?" + parse.urlencode(self.options)
if self.fragment:
result += "#" + self.fragment
return result
def __repr__(self):
return f"PlasterURL('{self}')"
[docs]
def parse_uri(config_uri):
"""
Parse the ``config_uri`` into a :class:`plaster.PlasterURL` object.
``config_uri`` can be a relative or absolute file path such as
``development.ini`` or ``/path/to/development.ini``. The file must have
an extension that can be handled by a :class:`plaster.ILoader`
registered with the system.
Alternatively, ``config_uri`` may be a :rfc:`1738`-style string.
"""
if isinstance(config_uri, PlasterURL):
return config_uri
# force absolute paths to look like a uri for more accurate parsing
# we throw away the dummy scheme later and parse it from the resolved
# path extension
isabs = os.path.isabs(config_uri)
if isabs:
config_uri = "dummy://" + config_uri
# check if the uri is actually a url
parts = parse.urlparse(config_uri)
# reconstruct the path without the scheme and fragment
path = parse.ParseResult(
scheme="",
netloc=parts.netloc,
path=parts.path,
params="",
query="",
fragment="",
).geturl()
# strip off leading //
if path.startswith("//"):
path = path[2:]
if parts.scheme and not isabs:
scheme = parts.scheme
else:
scheme = os.path.splitext(path)[1]
if scheme.startswith("."):
scheme = scheme[1:]
# tag uris coming from file extension as file+scheme
if scheme:
scheme = "file+" + scheme
query = parts.query if parts.query else None
options = OrderedDict()
if query:
options.update(parse.parse_qsl(query))
fragment = parts.fragment if parts.fragment else None
if not scheme:
raise InvalidURI(
config_uri,
(
"Could not determine the loader scheme for the supplied "
'config_uri "{}"'.format(config_uri)
),
)
return PlasterURL(scheme=scheme, path=path, options=options, fragment=fragment)