Exemplo n.º 1
0
 def test_authority(self):
     cases = [
         ('', None),
         ('//', ''),
         ('//', b''),
         ('//example.com', 'example.com'),
         ('//example.com', b'example.com'),
         ('//example.com', 'example.com:'),
         ('//example.com', b'example.com:'),
         ('//[email protected]', '*****@*****.**'),
         ('//[email protected]', b'*****@*****.**'),
         ('//example.com:42', 'example.com:42'),
         ('//example.com:42', b'example.com:42'),
         ('//[email protected]:42', '[email protected]:42'),
         ('//[email protected]:42', b'[email protected]:42'),
         ('//[email protected]:42', '[email protected]:42'),
         ('//[email protected]:42', b'[email protected]:42'),
         ('//user@[::1]:42', 'user@[::1]:42'),
         ('//user@[::1]:42', b'user@[::1]:42'),
         ('//user:[email protected]', 'user:[email protected]'),
         ('//user:[email protected]', b'user:[email protected]'),
     ]
     for uri, authority in cases:
         self.check(uri, authority=authority)
     # invalid authority type
     for authority in (True, 42, 3.14, ipaddress.IPv6Address('::1')):
         with self.assertRaises(TypeError, msg='authority=%r' % authority):
             uricompose(authority=authority)
Exemplo n.º 2
0
 def _find_albums(self, query):
     statement = ('select id, album, day, month, year, '
                  'albumartist, disctotal, '
                  'mb_albumid, artpath, mb_albumartistid '
                  'from albums where 1=1 ')
     statement += self._build_statement(query, 'genre', 'genre')
     statement += self._build_statement(query, 'artist', 'albumartist')
     statement += self._build_statement(query, 'album', 'album')
     statement += self._build_statement(query, 'mb_albumid', 'mb_albumid')
     statement += self._build_statement(query, 'date', 'year')
     result = self._query_beets_db(statement)
     albums = []
     for row in result:
         date = self._build_date(row[4], row[3], row[2])
         artist = Artist(name=row[5],
                         musicbrainz_id=row[9],
                         uri=uricompose('beetslocal', None,
                                        'artist:%s:' % row[9]))
         albums.append(
             Album(
                 name=row[1],
                 date=date,
                 artists=[artist],
                 # num_tracks=row[6],
                 num_discs=row[6],
                 musicbrainz_id=row[7],
                 # images=[row[8]],
                 uri=uricompose('beetslocal', None, 'album:%s:' % row[0])))
     return albums
Exemplo n.º 3
0
def uri(identifier='', filename=None, scheme=Extension.ext_name, **kwargs):
    if filename:
        return uritools.uricompose(scheme, path=identifier, fragment=filename)
    elif kwargs:
        return uritools.uricompose(scheme, path=identifier, query=kwargs)
    else:
        return '%s:%s' % (scheme, identifier)
Exemplo n.º 4
0
    def _browse_directory(self, uri, order=('type', 'name')):
        query = dict(uritools.urisplit(uri).getquerylist())
        type = query.pop('type', None)
        role = query.pop('role', None)

        # TODO: handle these in schema (generically)?
        if type == 'date':
            format = query.get('format', '%Y-%m-%d')
            return map(_dateref, schema.dates(self._connect(), format=format))
        if type == 'genre':
            return map(_genreref, schema.list_distinct(self._connect(), 'genre'))  # noqa

        # Fix #38: keep sort order of album tracks; this also applies
        # to composers and performers
        if type == Ref.TRACK and 'album' in query:
            order = ('disc_no', 'track_no', 'name')

        roles = role or ('artist', 'albumartist')  # FIXME: re-think 'roles'...

        refs = []
        for ref in schema.browse(self._connect(), type, order, role=roles, **query):  # noqa
            if ref.type == Ref.TRACK or (not query and not role):
                refs.append(ref)
            elif ref.type == Ref.ALBUM:
                refs.append(Ref.directory(uri=uritools.uricompose(
                    'local', None, 'directory', dict(query, type=Ref.TRACK, album=ref.uri)  # noqa
                ), name=ref.name))
            elif ref.type == Ref.ARTIST:
                refs.append(Ref.directory(uri=uritools.uricompose(
                    'local', None, 'directory', dict(query, **{role: ref.uri})
                ), name=ref.name))
            else:
                logger.warn('Unexpected SQLite browse result: %r', ref)
        return refs
Exemplo n.º 5
0
def uri(identifier="", filename=None, scheme=Extension.ext_name, **kwargs):
    if filename:
        return uritools.uricompose(scheme, path=identifier, fragment=filename)
    elif kwargs:
        return uritools.uricompose(scheme, path=identifier, query=kwargs)
    else:
        return f"{scheme}:{identifier}"
Exemplo n.º 6
0
 def _find_albums(self, query):
     statement = ('select id, album, day, month, year, '
                  'albumartist, disctotal, '
                  'mb_albumid, artpath, mb_albumartistid '
                  'from albums where 1=1 ')
     statement += self._build_statement(query, 'genre', 'genre')
     statement += self._build_statement(query, 'artist', 'albumartist')
     statement += self._build_statement(query, 'album', 'album')
     statement += self._build_statement(query, 'mb_albumid', 'mb_albumid')
     statement += self._build_statement(query, 'date', 'year')
     result = self._query_beets_db(statement)
     albums = []
     for row in result:
         date = self._build_date(row[4], row[3], row[2])
         artist = Artist(name=row[5],
                         musicbrainz_id=row[9],
                         uri=uricompose('beetslocal',
                                        None,
                                        'artist:%s:' % row[9]))
         albums.append(Album(name=row[1],
                             date=date,
                             artists=[artist],
                             # num_tracks=row[6],
                             num_discs=row[6],
                             musicbrainz_id=row[7],
                             # images=[row[8]],
                             uri=uricompose('beetslocal',
                                            None,
                                            'album:%s:' % row[0])))
     return albums
Exemplo n.º 7
0
 def test_authority(self):
     cases = [
         ('', None),
         ('//', ''),
         ('//', b''),
         ('//example.com', 'example.com'),
         ('//example.com', b'example.com'),
         ('//example.com', 'example.com:'),
         ('//example.com', b'example.com:'),
         ('//[email protected]', '*****@*****.**'),
         ('//[email protected]', b'*****@*****.**'),
         ('//example.com:42', 'example.com:42'),
         ('//example.com:42', b'example.com:42'),
         ('//[email protected]:42', '[email protected]:42'),
         ('//[email protected]:42', b'[email protected]:42'),
         ('//[email protected]:42', '[email protected]:42'),
         ('//[email protected]:42', b'[email protected]:42'),
         ('//user@[::1]:42', 'user@[::1]:42'),
         ('//user@[::1]:42', b'user@[::1]:42'),
         ('//user:[email protected]', 'user:[email protected]'),
         ('//user:[email protected]', b'user:[email protected]'),
     ]
     for uri, authority in cases:
         self.check(uri, authority=authority)
     # invalid authority type
     for authority in (True, 42, 3.14, ipaddress.IPv6Address('::1')):
         with self.assertRaises(TypeError, msg='authority=%r' % authority):
             uricompose(authority=authority)
Exemplo n.º 8
0
 def _find_tracks(self, query):
     statement = ('select id, title, day, month, year, artist, album, '
                  'composer, track, disc, length,  bitrate, comments, '
                  'mb_trackid, mtime, genre, tracktotal, disctotal, '
                  'mb_albumid, mb_albumartistid, albumartist, mb_artistid '
                  'from items where 1=1 ')
     statement += self._build_statement(query, 'track_name', 'title')
     statement += self._build_statement(query, 'genre', 'genre')
     statement += self._build_statement(query, 'artist', 'artist')
     statement += self._build_statement(query, 'album', 'album')
     statement += self._build_statement(query, 'composer', 'composer')
     statement += self._build_statement(query, 'mb_trackid', 'mb_trackid')
     statement += self._build_statement(query, 'mb_albumid', 'mb_albumid')
     statement += self._build_statement(query, 'mb_albumartistid',
                                        'mb_albumartistid')
     statement += self._build_statement(query, 'date', 'year')
     tracks = []
     result = self._query_beets_db(statement)
     for row in result:
         date = self._build_date(row[4], row[3], row[2])
         artist = Artist(name=row[5],
                         musicbrainz_id=row[21],
                         uri=uricompose('beetslocal', None,
                                        'artist:%s:' % row[21]))
         albumartist = Artist(name=row[20],
                              musicbrainz_id=row[19],
                              uri=uricompose('beetslocal', None,
                                             'artist:%s:' % row[19]))
         composer = Artist(name=row[7],
                           musicbrainz_id='',
                           uri=uricompose('beetslocal', None,
                                          'composer:%s:' % row[7]))
         album = Album(name=row[6],
                       date=date,
                       artists=[albumartist],
                       num_tracks=row[16],
                       num_discs=row[17],
                       musicbrainz_id=row[18],
                       uri=uricompose('beetslocal', None,
                                      'mb_album:%s:' % row[18]))
         tracks.append(
             Track(name=row[1],
                   artists=[artist],
                   album=album,
                   composers=[composer],
                   track_no=row[8],
                   disc_no=row[9],
                   date=date,
                   length=int(row[10] * 1000),
                   bitrate=row[11],
                   comment=row[12],
                   musicbrainz_id=row[13],
                   last_modified=int(row[14] * 1000),
                   genre=row[15],
                   uri=uricompose('beetslocal', None,
                                  'track:%s:' % row[0])))
     return tracks
Exemplo n.º 9
0
    def _browse_directory(self, uri, order=("type", "name COLLATE NOCASE")):
        query = dict(uritools.urisplit(uri).getquerylist())
        type = query.pop("type", None)
        role = query.pop("role", None)

        # TODO: handle these in schema (generically)?
        if type == "date":
            format = query.get("format", "%Y-%m-%d")
            return list(
                map(date_ref, schema.dates(self._connect(), format=format)))
        if type == "genre":
            return list(
                map(genre_ref, schema.list_distinct(self._connect(), "genre")))

        # Fix #38: keep sort order of album tracks; this also applies
        # to composers and performers
        if type == Ref.TRACK and "album" in query:
            order = ("disc_no", "track_no", "name")
        if type == Ref.ARTIST and self._config["use_artist_sortname"]:
            order = ("coalesce(sortname, name) COLLATE NOCASE", )
        roles = role or ("artist", "albumartist")  # FIXME: re-think 'roles'...

        refs = []
        for ref in schema.browse(self._connect(),
                                 type,
                                 order,
                                 role=roles,
                                 **query):  # noqa
            if ref.type == Ref.TRACK or (not query and not role):
                refs.append(ref)
            elif ref.type == Ref.ALBUM:
                refs.append(
                    Ref.directory(
                        uri=uritools.uricompose(
                            "local",
                            None,
                            "directory",
                            dict(query, type=Ref.TRACK, album=ref.uri),  # noqa
                        ),
                        name=ref.name,
                    ))
            elif ref.type == Ref.ARTIST:
                refs.append(
                    Ref.directory(
                        uri=uritools.uricompose("local", None, "directory",
                                                dict(query, **{role:
                                                               ref.uri})),
                        name=ref.name,
                    ))
            else:
                logger.warning("Unexpected SQLite browse result: %r", ref)
        return refs
Exemplo n.º 10
0
 def test_scheme(self):
     cases = [
         ('foo+bar:', 'foo+bar'),
         ('foo+bar:', b'foo+bar'),
         ('foo+bar:', 'FOO+BAR'),
         ('foo+bar:', b'FOO+BAR'),
     ]
     for uri, scheme in cases:
         self.check(uri, scheme=scheme)
     # invalid scheme
     for scheme in ('', 'foo:', '\xf6lk\xfcrbis'):
         with self.assertRaises(ValueError, msg='scheme=%r' % scheme):
             uricompose(scheme=scheme)
Exemplo n.º 11
0
 def test_scheme(self):
     cases = [
         ('foo+bar:', 'foo+bar'),
         ('foo+bar:', b'foo+bar'),
         ('foo+bar:', 'FOO+BAR'),
         ('foo+bar:', b'FOO+BAR'),
     ]
     for uri, scheme in cases:
         self.check(uri, scheme=scheme)
     # invalid scheme
     for scheme in ('', 'foo:', '\xf6lk\xfcrbis'):
         with self.assertRaises(ValueError, msg='scheme=%r' % scheme):
             uricompose(scheme=scheme)
Exemplo n.º 12
0
 def root_directory(self):
     root = self.__browse_root
     if not root:
         return None
     elif root.startswith(('file:', 'http:', 'https:')):
         uri = uritools.uridefrag('podcast+' + root).uri
     elif os.path.isabs(root):
         uri = uritools.uricompose('podcast+file', '', root)
     elif self.__config_dir:
         uri = uritools.uricompose('podcast+file', '',
                                   os.path.join(self.__config_dir, root))
     else:
         return None
     return models.Ref.directory(name='Podcasts', uri=uri)
Exemplo n.º 13
0
 def browse(self, uri):
     logger.debug(u'browse called with uri %s' % uri)
     result = []
     localpath = urisplit(uri).path
     # import pdb; pdb.set_trace()
     if localpath == 'root':
         result = self._media_dirs()
     else:
         directory = localpath
         logger.debug(u'directory is %s' % directory)
         for name in os.listdir(directory):
             child = os.path.join(directory, name)
             uri = uricompose(self.URI_PREFIX, None, child)
             if self.backend._follow_symlinks:
                 st = os.stat(child)
             else:
                 st = os.lstat(child)
             if not self.backend._show_hidden and name.startswith(b'.'):
                 continue
             elif stat.S_ISDIR(st.st_mode):
                 result.append(models.Ref.directory(name=name, uri=uri))
             elif stat.S_ISREG(st.st_mode):
                 result.append(models.Ref.track(name=name, uri=uri))
             else:
                 logger.warn(u'Strange file encountered %s' % child)
                 pass
     result.sort(key=operator.attrgetter('name'))
     return result
Exemplo n.º 14
0
 def search(self, query=None, uris=None, exact=False):
     logger.debug(u'Search query: %s in uris: %s' % (query, uris))
     # import pdb; pdb.set_trace()
     query = self._sanitize_query(query)
     logger.debug(u'Search sanitized query: %s ' % query)
     if exact:
         return self._find_exact(query, uris)
     albums = []
     if not query:
         uri = 'beetslocal:search-all'
         tracks = self.lib.items()
         albums = self.lib.albums()
     else:
         uri = uricompose('beetslocal', None, 'search', query)
         track_query = self._build_beets_track_query(query)
         logger.debug(u'Build Query "%s":' % track_query)
         tracks = self.lib.items(track_query)
         if 'track_name' not in query:
             # when trackname queried dont search for albums
             album_query = self._build_beets_album_query(query)
             logger.debug('Build Query "%s":' % album_query)
             albums = self.lib.albums(album_query)
     logger.debug(u"Query found %s tracks and %s albums" %
                  (len(tracks), len(albums)))
     return SearchResult(
         uri=uri,
         tracks=[self._convert_item(track) for track in tracks],
         albums=[self._convert_album(album) for album in albums])
Exemplo n.º 15
0
def _lastmodifiedref(option):
    timestamp = int(time.time()) - option[0] * 24*60*1000
    return Ref.directory(
        uri=uritools.uricompose('local', None, 'directory',
                                {'last_modified': timestamp}),
        name=option[1]
    )
Exemplo n.º 16
0
 def search(self, query=None, uris=None):
     albums = []
     logger.debug("Search query: %s in uris: %s" % (query, uris))
     if not query:
         uri = 'beetslocal:search-all'
         tracks = self.lib.items()
         # albums = self.lib.albums()
         # albums not used til advanced_search
     else:
         uri = uricompose('beetslocal',
                          None,
                          'search',
                          query)
         self._validate_query(query)
         track_query = self._build_beets_track_query(query)
         logger.debug('Build Query "%s":' % track_query)
         tracks = self.lib.items(track_query)
         # if not 'track_name' in query:
         # when trackname queried dont search for albums
         #    album_query = self._build_beets_album_query(query)
         #    logger.debug('Build Query "%s":' % album_query)
         #    albums = self.lib.albums(album_query)
     logger.debug("Query found %s tracks and %s albums"
                  % (len(tracks), len(albums)))
     return SearchResult(
         uri=uri,
         tracks=[self._convert_item(track) for track in tracks]
         # albums=[self._convert_album(album) for album in albums]
     )
Exemplo n.º 17
0
def _album(metadata, images=[]):
    identifier = metadata['identifier']
    uri = uritools.uricompose(SCHEME, path=identifier)
    name = metadata.get('title', identifier)
    artists = parse_creator(metadata.get('creator'))
    date = parse_date(metadata.get('date'))
    return Album(uri=uri, name=name, artists=artists, date=date, images=images)
    def __init__(self, config):
        if not set(("uri", "name", "user", "password")).issubset(config):
            raise ValueError("Incomplete config dictionary")

        # QUESTION thread local connection (pool) vs sharing a serialized connection, pro/cons?
        # from sqlalchemy.orm import sessionmaker, scoped_session
        # Session = scoped_session(sessionmaker(bind=engine))
        # when using a connection pool how do we prevent notifiying ourself on database changes?
        self.lock = Lock()
        self.notify = None

        uri_parts = urisplit(config["uri"])

        if self.DIALECT_SQLITE == uri_parts.scheme:
            self.engine = create_engine(
                config["uri"], connect_args={"check_same_thread": False})
            self.conn = self.engine.connect()
            self.conn.execute(
                text("PRAGMA foreign_keys = ON").execution_options(
                    autocommit=True))
        elif self.DIALECT_POSTGRESQL == uri_parts.scheme:
            uri = uricompose(scheme=uri_parts.scheme,
                             host=uri_parts.host,
                             port=uri_parts.getport(default=5432),
                             path="/{}".format(config["name"]),
                             userinfo="{}:{}".format(config["user"],
                                                     config["password"]))
            self.engine = create_engine(uri)
            self.conn = self.engine.connect()
            self.notify = PGNotify(uri)
        else:
            raise ValueError("Engine '{engine}' not supported".format(
                engine=uri_parts.scheme))
Exemplo n.º 19
0
 def search(self, query=None, uris=None, exact=False):
     logger.debug(u'Search query: %s in uris: %s' % (query, uris))
     # import pdb; pdb.set_trace()
     query = self._sanitize_query(query)
     logger.debug(u'Search sanitized query: %s ' % query)
     if exact:
         return self._find_exact(query, uris)
     albums = []
     if not query:
         uri = 'beetslocal:search-all'
         tracks = self.lib.items()
         albums = self.lib.albums()
     else:
         uri = uricompose('beetslocal',
                          None,
                          'search',
                          query)
         track_query = self._build_beets_track_query(query)
         logger.debug(u'Build Query "%s":' % track_query)
         tracks = self.lib.items(track_query)
         if 'track_name' not in query:
             # when trackname queried dont search for albums
             album_query = self._build_beets_album_query(query)
             logger.debug('Build Query "%s":' % album_query)
             albums = self.lib.albums(album_query)
     logger.debug(u"Query found %s tracks and %s albums"
                  % (len(tracks), len(albums)))
     return SearchResult(
         uri=uri,
         tracks=[self._convert_item(track) for track in tracks],
         albums=[self._convert_album(album) for album in albums]
     )
Exemplo n.º 20
0
 def _path_in_url(self, key):
     return uritools.uricompose(
         scheme='http',
         host=self.endpoint,
         port=self.port,
         path='/v2/keys/{}'.format(key.lstrip('/'))
     )
Exemplo n.º 21
0
 def browse(self, uri):
     logger.debug(u"Browse being called for %s" % uri)
     level = urisplit(uri).path
     query = self._sanitize_query(dict(urisplit(uri).getquerylist()))
     logger.debug("Got parsed to level: %s - query: %s" % (level,
                                                           query))
     result = []
     if not level:
         logger.error("No level for uri %s" % uri)
         # import pdb; pdb.set_trace()
     if level == 'root':
         for row in self._browse_genre():
             result.append(Ref.directory(
                 uri=uricompose('beetslocal',
                                None,
                                'genre',
                                dict(genre=row[0])),
                 name=row[0] if bool(row[0]) else u'No Genre'))
     elif level == "genre":
         # artist refs not browsable via mpd
         for row in self._browse_artist(query):
             result.append(Ref.directory(
                 uri=uricompose('beetslocal',
                                None,
                                'artist',
                                dict(genre=query['genre'][0],
                                     artist=row[1])),
                 name=row[0] if bool(row[0]) else u'No Artist'))
     elif level == "artist":
         for album in self._browse_album(query):
             result.append(Ref.album(
                 uri=uricompose('beetslocal',
                                None,
                                'album',
                                dict(album=album.id)),
                 name=album.album))
     elif level == "album":
         for track in self._browse_track(query):
             result.append(Ref.track(
                 uri="beetslocal:track:%s:%s" % (
                     track.id,
                     uriencode(track.path, '/')),
                 name=track.title))
     else:
         logger.debug('Unknown URI: %s', uri)
     # logger.debug(result)
     return result
Exemplo n.º 22
0
 def root_directory(self):
     root = self.__browse_root
     if not root:
         return None
     elif root.startswith(('file:', 'http:', 'https:')):
         uri = uritools.uridefrag('podcast+' + root).uri
         return models.Ref.directory(name='Podcasts', uri=uri)
     elif os.path.isabs(root):
         uri = uritools.uricompose('podcast+file', '', root)
         return models.Ref.directory(name='Podcasts', uri=uri)
     elif self.__config_dir:
         path = os.path.join(self.__config_dir, root)
         uri = uritools.uricompose('podcast+file', '', path)
         return models.Ref.directory(name='Podcasts', uri=uri)
     else:
         logger.error('Cannot retrieve Podcast root directory')
         return None
Exemplo n.º 23
0
 def __add_server(self, obj):
     udn = obj['UDN']
     obj['URI'] = uritools.uricompose(Extension.ext_name, udn)
     key = udn.lower()
     if key not in self:
         self.__log_server_action('Found', obj)
     with self.__lock:
         self.__servers[key] = obj
Exemplo n.º 24
0
    def test_query(self):
        from collections import OrderedDict as od

        cases = [
            ('?', ''),
            ('?', b''),
            ('?', []),
            ('?', {}),
            ('?name', 'name'),
            ('?name', b'name'),
            ('?name', [('name', None)]),
            ('?name', [(b'name', None)]),
            ('?name', {'name': None}),
            ('?name', {b'name': None}),
            ('?name=foo', 'name=foo'),
            ('?name=foo', b'name=foo'),
            ('?name=foo', [('name', 'foo')]),
            ('?name=foo', [('name', b'foo')]),
            ('?name=foo', [(b'name', b'foo')]),
            ('?name=foo', {'name': 'foo'}),
            ('?name=foo', {'name': b'foo'}),
            ('?name=foo', {'name': ['foo']}),
            ('?name=foo', {'name': [b'foo']}),
            ('?name=foo', {b'name': b'foo'}),
            ('?name=foo', {b'name': [b'foo']}),
            ('?name=42', [('name', 42)]),
            ('?name=42', {'name': 42}),
            ('?name=42', {'name': [42]}),
            ('?name=foo&type=bar', [('name', 'foo'), ('type', 'bar')]),
            ('?name=foo&type=bar', od([('name', 'foo'), ('type', 'bar')])),
            ('?name=foo&name=bar', [('name', 'foo'), ('name', 'bar')]),
            ('?name=foo&name=bar', {'name': ['foo', 'bar']}),
            ('?name=a/b/c', dict(name='a/b/c')),
            ('?name=a:b:c', dict(name='a:b:c')),
            ('?name=a?b?c', dict(name='a?b?c')),
            ('?name=a@b@c', dict(name='a@b@c')),
            ('?name=a%23b%23c', dict(name='a#b#c')),
            ('?name=a%26b%26c', dict(name='a&b&c')),
            ('?name=a%3Bb%3Bc', dict(name='a;b;c')),
        ]
        for uri, query in cases:
            self.check(uri, query=query)
        # invalid query type
        for query in (0, [1]):
            with self.assertRaises(TypeError, msg='query=%r' % query):
                uricompose(query=query)
Exemplo n.º 25
0
def _ref(metadata):
    identifier = metadata['identifier']
    uri = uritools.uricompose(SCHEME, path=identifier)
    name = metadata.get('title', identifier)
    if metadata.get('mediatype', 'collection') == 'collection':
        return Ref.directory(uri=uri, name=name)
    else:
        return Ref.album(uri=uri, name=name)
Exemplo n.º 26
0
 def __add_server(self, obj):
     udn = obj["UDN"]
     obj["URI"] = uritools.uricompose(Extension.ext_name, udn)
     key = udn.lower()
     if key not in self:
         self.__log_server_action("Found", obj)
     with self.__lock:
         self.__servers[key] = obj
Exemplo n.º 27
0
 def parametrizeUri(baseUri, params):
     parts = uritools.urisplit(baseUri)
     uri = uritools.uricompose(parts.scheme,
                               parts.host,
                               parts.path,
                               params,
                               port=parts.port)
     return uri
Exemplo n.º 28
0
 def _media_dirs(self):
     result = []
     for media_dir in self.backend.media_dirs:
         dir = models.Ref.directory(
             name=media_dir['name'],
             uri=uricompose(self.URI_PREFIX, None, media_dir['path']))
         result.append(dir)
     return result
Exemplo n.º 29
0
 def search(self, query=None, limit=100, offset=0, uris=None, exact=False):
     q = []
     for field, values in query.items() if query else []:
         q.extend((field, value) for value in values)
     filters = [f for uri in uris or [] for f in self._filters(uri) if f]
     with self._connect() as c:
         tracks = schema.search_tracks(c, q, limit, offset, exact, filters)
     uri = uritools.uricompose("local", path="search", query=q)
     return SearchResult(uri=uri, tracks=tracks)
Exemplo n.º 30
0
 def search(self, query=None, limit=100, offset=0, uris=None, exact=False):
     q = []
     for field, values in (query.items() if query else []):
         q.extend((field, value) for value in values)
     filters = [f for uri in uris or [] for f in self._filters(uri) if f]
     with self._connect() as c:
         tracks = schema.search_tracks(c, q, limit, offset, exact, filters)
     uri = uritools.uricompose('local', path='search', query=q)
     return SearchResult(uri=uri, tracks=tracks)
Exemplo n.º 31
0
    def _convert_album(self, album):
        """
        Transforms a beets album into a mopidy Track
        """
        if not album:
            return
        album_kwargs = {}
        artist_kwargs = {}

        if 'album' in album:
            album_kwargs['name'] = album['album']

        if 'disctotal' in album:
            album_kwargs['num_discs'] = album['disctotal']

        if 'tracktotal' in album:
            album_kwargs['num_tracks'] = album['tracktotal']

        if 'mb_albumid' in album:
            album_kwargs['musicbrainz_id'] = album['mb_albumid']

        album_kwargs['date'] = None
        if self.backend.use_original_release_date:
            if 'original_year' in album:
                    album_kwargs['date'] = self._build_date(
                                                album['original_year'],
                                                album['original_month'],
                                                album['original_day'])
        else:
            if 'year' in album:
                    album_kwargs['date'] = self._build_date(album['year'],
                                                            album['month'],
                                                            album['day'])

        # if 'added' in item:
        #    album_kwargs['last_modified'] = album['added']

        # if 'artpath' in album:
        #    album_kwargs['images'] = [album['artpath']]

        if 'albumartist' in album:
            artist_kwargs['name'] = album['albumartist']

        if 'mb_albumartistid' in album:
            artist_kwargs['musicbrainz_id'] = album['mb_albumartistid']

        if artist_kwargs:
            artist = Artist(**artist_kwargs)
            album_kwargs['artists'] = [artist]

        if 'id' in album:
            album_kwargs['uri'] = uricompose('beetslocal',
                                             None,
                                             'album:%s:' % album['id'])

        album = Album(**album_kwargs)
        return album
Exemplo n.º 32
0
 def _search(self, *terms):
     result = self.backend.client.search(
         _query(*terms, **self._search_filter),
         fields=['identifier', 'title', 'creator', 'date'],
         sort=self._config['search_order'],
         rows=self._config['search_limit']
     )
     uri = uricompose(Extension.ext_name, query=result.query)
     return SearchResult(uri=uri, albums=[_album(doc) for doc in result])
Exemplo n.º 33
0
    def _browse_directory(self, uri):
        query = dict(uritools.urisplit(str(uri)).getquerylist())
        type = query.pop('type', None)
        role = query.pop('role', None)
        # TODO: handle these in schema (generically)?
        if type == 'date':
            format = query.get('format', '%Y-%m-%d')
            return map(_dateref, schema.dates(self._connect(), format=format))
        if type == 'genre':
            return map(_genreref, schema.genres(self._connect()))
        if type == 'last_modified':
            return map(_lastmodifiedref,
                       ((7, 'Last 7 days'),
                       (30, 'Last month'),
                       (92, 'Last 3 months'),
                       (157, 'Last 6 months'),
                       (365, 'Last year'))
            )

        roles = role or ('artist', 'albumartist')

        refs = []
        for ref in schema.browse(self._connect(), type, role=roles, **query):
            if ref.type == Ref.TRACK or (not query and not role):
                # FIXME: artist refs not browsable via mpd
                if ref.type == Ref.ARTIST:
                    refs.append(ref.copy(type=Ref.DIRECTORY))
                else:
                    refs.append(ref)
            elif ref.type == Ref.ALBUM:
                uri = uritools.uricompose('local', None, 'directory', dict(
                    query, type=Ref.TRACK, album=ref.uri
                ))
                refs.append(Ref.directory(uri=uri, name=ref.name))
            elif ref.type == Ref.ARTIST:
                uri = uritools.uricompose('local', None, 'directory', dict(
                    query, **{role: ref.uri}
                ))
                refs.append(Ref.directory(uri=uri, name=ref.name))
            else:
                logger.warn('Unexpected SQLite browse result: %r', ref)
        return refs
Exemplo n.º 34
0
    def _convert_album(self, album):
        """
        Transforms a beets album into a mopidy Track
        """
        if not album:
            return
        album_kwargs = {}
        artist_kwargs = {}

        if 'album' in album:
            album_kwargs['name'] = album['album']

        if 'disctotal' in album:
            album_kwargs['num_discs'] = album['disctotal']

        if 'tracktotal' in album:
            album_kwargs['num_tracks'] = album['tracktotal']

        if 'mb_albumid' in album:
            album_kwargs['musicbrainz_id'] = album['mb_albumid']

        album_kwargs['date'] = None
        if self.backend.use_original_release_date:
            if 'original_year' in album:
                album_kwargs['date'] = self._build_date(
                    album['original_year'], album['original_month'],
                    album['original_day'])
        else:
            if 'year' in album:
                album_kwargs['date'] = self._build_date(
                    album['year'], album['month'], album['day'])

        # if 'added' in item:
        #    album_kwargs['last_modified'] = album['added']

        # if 'artpath' in album:
        #    album_kwargs['images'] = [album['artpath']]

        if 'albumartist' in album:
            artist_kwargs['name'] = album['albumartist']

        if 'mb_albumartistid' in album:
            artist_kwargs['musicbrainz_id'] = album['mb_albumartistid']

        if artist_kwargs:
            artist = Artist(**artist_kwargs)
            album_kwargs['artists'] = [artist]

        if 'id' in album:
            album_kwargs['uri'] = uricompose('beetslocal', None,
                                             'album:%s:' % album['id'])

        album = Album(**album_kwargs)
        return album
Exemplo n.º 35
0
 def browse(self, uri):
     logger.debug(u"Browse being called for %s" % uri)
     level = urisplit(uri).path
     query = self._sanitize_query(dict(urisplit(uri).getquerylist()))
     logger.debug("Got parsed to level: %s - query: %s" % (level, query))
     result = []
     if not level:
         logger.error("No level for uri %s" % uri)
         # import pdb; pdb.set_trace()
     if level == 'root':
         for row in self._browse_genre():
             result.append(
                 Ref.directory(
                     uri=uricompose('beetslocal', None, 'genre',
                                    dict(genre=row[0])),
                     name=row[0] if bool(row[0]) else u'No Genre'))
     elif level == "genre":
         # artist refs not browsable via mpd
         for row in self._browse_artist(query):
             result.append(
                 Ref.directory(
                     uri=uricompose(
                         'beetslocal', None, 'artist',
                         dict(genre=query['genre'][0], artist=row[1])),
                     name=row[0] if bool(row[0]) else u'No Artist'))
     elif level == "artist":
         for album in self._browse_album(query):
             result.append(
                 Ref.album(uri=uricompose('beetslocal', None, 'album',
                                          dict(album=album.id)),
                           name=album.album))
     elif level == "album":
         for track in self._browse_track(query):
             result.append(
                 Ref.track(uri="beetslocal:track:%s:%s" %
                           (track.id, uriencode(track.path, '/')),
                           name=track.title))
     else:
         logger.debug('Unknown URI: %s', uri)
     # logger.debug(result)
     return result
Exemplo n.º 36
0
def parse(source):
    if isinstance(source, basestring):
        url = uritools.uricompose('file', '', source)
    else:
        url = source.geturl()
    root = ElementTree.parse(source).getroot()
    if root.tag == 'rss':
        return RssFeed(url, root)
    elif root.tag == 'opml':
        return OpmlFeed(url, root)
    else:
        raise TypeError('Not a recognized podcast feed: %s', url)
Exemplo n.º 37
0
 def search(self, query=None, limit=100, offset=0, uris=None, exact=False):
     q = []
     for field, values in (query.items() if query else []):
         if isinstance(values, basestring):
             q.append((field, values))
         else:
             q.extend((field, value) for value in values)
     filters = [f for uri in uris or [] for f in self._filters(uri) if f]
     with self._connect() as c:
         tracks = schema.search_tracks(c, q, limit, offset, exact, filters)
     uri = uritools.uricompose('local', path='search', query=q)
     return SearchResult(uri=uri, tracks=tracks)
Exemplo n.º 38
0
def parse(source):
    if isinstance(source, basestring):
        url = uritools.uricompose('file', '', source)
    else:
        url = source.geturl()
    root = ElementTree.parse(source).getroot()
    if root.tag == 'rss':
        return RssFeed(url, root)
    elif root.tag == 'opml':
        return OpmlFeed(url, root)
    else:
        raise TypeError('Not a recognized podcast feed: %s', url)
Exemplo n.º 39
0
 def search(self, query=None, limit=100, offset=0, uris=None, exact=False):
     q = []
     for field, values in (query.items() if query else []):
         q.extend((field, value) for value in values)
     # temporary workaround until Mopidy core sets limit
     if self._config['search_limit'] is not None:
         limit = self._config['search_limit']
     filters = [f for uri in uris or [] for f in self._filters(uri) if f]
     with self._connect() as c:
         tracks = schema.search_tracks(c, q, limit, offset, exact, filters)
     uri = uritools.uricompose('local', path='search', query=q)
     return SearchResult(uri=uri, tracks=tracks)
Exemplo n.º 40
0
    def _browse_directory(self, uri):
        query = dict(uritools.urisplit(str(uri)).getquerylist())
        type = query.pop('type', None)
        role = query.pop('role', None)
        # TODO: handle these in schema (generically)?
        if type == 'date':
            format = query.get('format', '%Y-%m-%d')
            return map(_dateref, schema.dates(self._connect(), format=format))
        if type == 'genre':
            return map(_genreref, schema.genres(self._connect()))
        if type == 'last_modified':
            return map(_lastmodifiedref,
                       ((7, 'Last 7 days'), (30, 'Last month'),
                        (92, 'Last 3 months'), (157, 'Last 6 months'),
                        (365, 'Last year')))

        roles = role or ('artist', 'albumartist')

        refs = []
        for ref in schema.browse(self._connect(), type, role=roles, **query):
            if ref.type == Ref.TRACK or (not query and not role):
                # FIXME: artist refs not browsable via mpd
                if ref.type == Ref.ARTIST:
                    refs.append(ref.copy(type=Ref.DIRECTORY))
                else:
                    refs.append(ref)
            elif ref.type == Ref.ALBUM:
                uri = uritools.uricompose(
                    'local', None, 'directory',
                    dict(query, type=Ref.TRACK, album=ref.uri))
                refs.append(Ref.directory(uri=uri, name=ref.name))
            elif ref.type == Ref.ARTIST:
                uri = uritools.uricompose('local', None, 'directory',
                                          dict(query, **{role: ref.uri}))
                refs.append(Ref.directory(uri=uri, name=ref.name))
            else:
                logger.warn('Unexpected SQLite browse result: %r', ref)
        return refs
Exemplo n.º 41
0
    def compose(scheme=None,
                authority=None,
                path=None,
                query=None,
                fragment=None,
                port=None):

        parts = uritools.uricompose(scheme=scheme,
                                    host=authority,
                                    port=port,
                                    path=path,
                                    query=query,
                                    fragment=fragment)
        return uritools.uriunsplit(parts)
Exemplo n.º 42
0
 def test_path(self):
     cases = [
         ('foo', 'foo'),
         ('foo', b'foo'),
         ('foo+bar', 'foo+bar'),
         ('foo+bar', b'foo+bar'),
         ('foo%20bar', 'foo bar'),
         ('foo%20bar', b'foo bar'),
         ('./this:that', 'this:that'),
         ('./this:that', b'this:that'),
         ('./this:that/', 'this:that/'),
         ('./this:that/', b'this:that/'),
     ]
     for uri, path in cases:
         self.check(uri, path=path)
     # invalid path with authority
     for path in ('foo', b'foo'):
         with self.assertRaises(ValueError, msg='path=%r' % path):
             uricompose(authority='auth', path=path)
     # invalid path without authority
     for path in ('//', b'//', '//foo', b'//foo'):
         with self.assertRaises(ValueError, msg='path=%r' % path):
             uricompose(path=path)
Exemplo n.º 43
0
 def build_url(cls, base, additional_params=None):
     url = uritools.urisplit(base)
     query_params = url.getquerydict()
     if additional_params is not None:
         query_params.update(additional_params)
         for k, v in additional_params.items():
             if v is None:
                 query_params.pop(k)
     return uritools.uricompose(scheme=url.scheme,
                                host=url.host,
                                port=url.port,
                                path=url.path,
                                query=query_params,
                                fragment=url.fragment)
Exemplo n.º 44
0
 def test_path(self):
     cases = [
         ('foo', 'foo'),
         ('foo', b'foo'),
         ('foo+bar', 'foo+bar'),
         ('foo+bar', b'foo+bar'),
         ('foo%20bar', 'foo bar'),
         ('foo%20bar', b'foo bar'),
         ('./this:that', 'this:that'),
         ('./this:that', b'this:that'),
         ('./this:that/', 'this:that/'),
         ('./this:that/', b'this:that/'),
     ]
     for uri, path in cases:
         self.check(uri, path=path)
     # invalid path with authority
     for path in ('foo', b'foo'):
         with self.assertRaises(ValueError, msg='path=%r' % path):
             uricompose(authority='auth', path=path)
     # invalid path without authority
     for path in ('//', b'//', '//foo', b'//foo'):
         with self.assertRaises(ValueError, msg='path=%r' % path):
             uricompose(path=path)
Exemplo n.º 45
0
 def build_url(cls, base, additional_params=None):
     url = uritools.urisplit(base)
     query_params = url.getquerydict()
     if additional_params is not None:
         query_params.update(additional_params)
         for k, v in additional_params.items():
             if v is None:
                 query_params.pop(k)
     return uritools.uricompose(scheme=url.scheme,
                                 host=url.host,
                                 port=url.port,
                                 path=url.path,
                                 query=query_params,
                                 fragment=url.fragment)
Exemplo n.º 46
0
def build_uri(scheme=DEFAULT_SCALE_URI_SCHEME,
              namespace=DEFAULT_SCALE_URI_NAMESPACE,
              path=None,
              relative_path=None,
              **kwargs):
    """
    Build a URI from the specified parameters.  If you don't specify path to create a complete path,
     you can specify a relative path to have it build one for you on top of the optionally-specified
    namespace that helps avoid collision with core scale client URIs.

    NOTE: these parameters are just for conventional purposes and don't do any significant
     namespace separation, management, or API exposure currently...

    :param path: an absolute URI path (will skip over the namespace and relative one when present)
    :param scheme: first part of the URI identifying the protocol/scheme/etc. (default is scale-specific for local use)
    :param namespace: prepended on relative path (default is scale-specific); the scale core may handle the different namespaces separately
    :param relative_path: e.g. your/path/goes/here but note that you are responsible for managing this path hierarchy!
    :param kwargs: all these are passed to uritools.uricompose
    :return:
    """

    # First build up the path we'll use
    parts_to_use = []

    if not path and not relative_path:
        raise ValueError(
            "must specify at least a component path (can be a simple name string) or "
        )
    elif not path and relative_path:
        if namespace:
            parts_to_use.append(namespace)
        parts_to_use.append(relative_path)
    else:
        parts_to_use.append(path)
        # TODO: check for ignored args and warn user? only when logging enabled...
        # if relative_path:

    # First, trim any leading/trailing slashes
    final_parts = []
    for part in parts_to_use:
        while part.startswith('/'):
            part = part[1:]
        while part.endswith('/'):
            part = part[:-1]
        final_parts.append(part)
    # Note that we enforce a leading / for the path!
    path = '/' + '/'.join(final_parts)

    return uritools.uricompose(scheme=scheme, path=path, **kwargs)
Exemplo n.º 47
0
def _track(metadata, file, album):
    identifier = metadata['identifier']
    filename = file['name']
    uri = uritools.uricompose(SCHEME, path=identifier, fragment=filename)
    name = file.get('title', filename)
    return Track(
        uri=uri,
        name=name,
        album=album,
        artists=album.artists,
        track_no=parse_track(file.get('track')),
        date=parse_date(file.get('date'), album.date),
        length=parse_length(file.get('length')),
        bitrate=parse_bitrate(file.get('bitrate')),
        last_modified=parse_mtime(file.get('mtime'))
    )
Exemplo n.º 48
0
def get_safe_redirect_target(arg='next'):
    """Get URL to redirect to and ensure that it is local.

    :param arg: URL argument.
    :returns: The redirect target or ``None``.
    """
    for target in request.args.get(arg), request.referrer:
        if target:
            redirect_uri = uritools.urisplit(target)
            allowed_hosts = current_app.config.get('APP_ALLOWED_HOSTS', [])
            if redirect_uri.host in allowed_hosts:
                return target
            elif redirect_uri.path:
                return uritools.uricompose(path=redirect_uri.path,
                                           query=redirect_uri.query)
    return None
Exemplo n.º 49
0
 def test_you_can_register_and_login_using_an_unregistered_ssl_cert_with_email(
         self):
     certAttr = self.getCertAttributes()
     params = dict(email="*****@*****.**")
     parts = uritools.urisplit(Config.BASE_URL)
     url = uritools.uricompose(parts.scheme, parts.host, parts.path, params)
     self.controller.interface.set_request_context(url)
     self.controller.mail = FakeMail()
     resp = self.sslLoginWithCert(certAttr.cert)
     cred = Credential.get("certificate", certAttr.identifier)
     self.deleteUser(cred.user)
     self.assertEqual(resp.status_code, 200)
     responseText = self.getResponseText(resp)
     self.assertTrue(CREDENTIAL_REPRESENTATION in responseText)
     self.assertTrue(
         '{"credentialType": "emailcheck", "identifier":' in responseText)
Exemplo n.º 50
0
 def _browse_artist(self, uri, order=('type', 'name')):
     with self._connect() as c:
         albums = schema.browse(c, Ref.ALBUM, order, albumartist=uri)
         refs = schema.browse(c, order=order, artist=uri)
     uris, tracks = {ref.uri for ref in albums}, []
     for ref in refs:
         if ref.type == Ref.TRACK:
             tracks.append(ref)
         elif ref.type == Ref.ALBUM and ref.uri not in uris:
             uri = uritools.uricompose('local', None, 'directory', dict(
                 type=Ref.TRACK, album=ref.uri, artist=uri
             ))
             albums.append(Ref.directory(uri=uri, name=ref.name))
         else:
             logger.debug('Skipped SQLite browse result %s', ref.uri)
     albums.sort(key=operator.attrgetter('name'))
     return albums + tracks
Exemplo n.º 51
0
 def _find_artists(self, query):
     statement = ('select Distinct albumartist, mb_albumartistid'
                  ' from albums where 1=1 ')
     statement += self._build_statement(query, 'genre', 'genre')
     statement += self._build_statement(query, 'artist', 'albumartist')
     statement += self._build_statement(query, 'date', 'year')
     statement += self._build_statement(query, 'mb_albumartistid',
                                        'mb_albumartistid')
     artists = []
     result = self._query_beets_db(statement)
     for row in result:
         artists.append(
             Artist(name=row[0],
                    musicbrainz_id=row[1],
                    uri=uricompose('beetslocal', None,
                                   'artist:%s:' % row[1])))
     return artists
Exemplo n.º 52
0
    def load_uri(self, uri: str) -> dict:
        """Return the JSON object associated with given URI
        
        :param uri: URI string
        """
        result = urisplit(uri)

        location = uricompose(result.scheme, result.authority, result.path)
        loader = self.scheme_to_loader[result.scheme]
        resource = self.load_resource_from_loader(loader, location)

        if result.fragment:
            assert result.fragment.startswith("/")
            reference = Reference(result.fragment[1:])
            return reference.extract(resource)

        return resource
Exemplo n.º 53
0
 def _find_artists(self, query):
     statement = ('select Distinct albumartist, mb_albumartistid'
                  ' from albums where 1=1 ')
     statement += self._build_statement(query, 'genre', 'genre')
     statement += self._build_statement(query, 'artist', 'albumartist')
     statement += self._build_statement(query, 'date', 'year')
     statement += self._build_statement(query,
                                        'mb_albumartistid',
                                        'mb_albumartistid')
     artists = []
     result = self._query_beets_db(statement)
     for row in result:
         artists.append(Artist(name=row[0],
                               musicbrainz_id=row[1],
                               uri=uricompose('beetslocal',
                                              None,
                                              'artist:%s:' % row[1])))
     return artists
Exemplo n.º 54
0
def build_uri(scheme=DEFAULT_SCALE_URI_SCHEME, namespace=DEFAULT_SCALE_URI_NAMESPACE,
              path=None, relative_path=None, **kwargs):
    """
    Build a URI from the specified parameters.  If you don't specify path to create a complete path,
     you can specify a relative path to have it build one for you on top of the optionally-specified
    namespace that helps avoid collision with core scale client URIs.

    NOTE: these parameters are just for conventional purposes and don't do any significant
     namespace separation, management, or API exposure currently...

    :param path: an absolute URI path (will skip over the namespace and relative one when present)
    :param scheme: first part of the URI identifying the protocol/scheme/etc. (default is scale-specific for local use)
    :param namespace: prepended on relative path (default is scale-specific); the scale core may handle the different namespaces separately
    :param relative_path: e.g. your/path/goes/here but note that you are responsible for managing this path hierarchy!
    :param kwargs: all these are passed to uritools.uricompose
    :return:
    """

    # First build up the path we'll use
    parts_to_use = []

    if not path and not relative_path:
        raise ValueError("must specify at least a component path (can be a simple name string) or ")
    elif not path and relative_path:
        if namespace:
            parts_to_use.append(namespace)
        parts_to_use.append(relative_path)
    else:
        parts_to_use.append(path)
        # TODO: check for ignored args and warn user? only when logging enabled...
        # if relative_path:

    # First, trim any leading/trailing slashes
    final_parts = []
    for part in parts_to_use:
        while part.startswith('/'):
            part = part[1:]
        while part.endswith('/'):
            part = part[:-1]
        final_parts.append(part)
    # Note that we enforce a leading / for the path!
    path = '/' + '/'.join(final_parts)

    return uritools.uricompose(scheme=scheme, path=path, **kwargs)
Exemplo n.º 55
0
 def _find_exact(self, query=None, uris=None):
     logger.debug("Find query: %s in uris: %s" % (query, uris))
     # artists = []
     albums = []
     if not (('track_name' in query) or ('composer' in query)):
         # when trackname or composer is queried dont search for albums
         albums = self._find_albums(query)
         logger.debug("Find found %s albums" % len(albums))
     #    artists=self._find_artists(query)
     #    logger.debug("Find found %s artists" % len(artists))
     tracks = self._find_tracks(query)
     logger.debug(u'Find found %s tracks' % len(tracks))
     return SearchResult(
         uri=uricompose('beetslocal',
                        None,
                        'find',
                        query),
         # artists=artists,
         albums=albums,
         tracks=tracks)
Exemplo n.º 56
0
    def _compose_url(self, url, kwargs):
        """
        Compose a URL starting with the given URL (or self.url if that URL is
        None) and using the values in kwargs.

        :param str url:
            The base URL to use. If None, ``self.url`` will be used instead.
        :param dict kwargs:
            A dictionary of values to override in the base URL. Relevant keys
            will be popped from the dictionary.
        """
        if url is None:
            url = self.url

        if url is None:
            raise ValueError(
                'url not provided and this client has no url attribute')

        split_result = urisplit(url)
        userinfo = split_result.userinfo

        # Build up the kwargs to pass to uricompose
        compose_kwargs = {}
        for key in ['scheme', 'host', 'port', 'path', 'fragment']:
            if key in kwargs:
                compose_kwargs[key] = kwargs.pop(key)
            else:
                compose_kwargs[key] = getattr(split_result, key)

        if 'params' in kwargs:
            compose_kwargs['query'] = kwargs.pop('params')
        else:
            compose_kwargs['query'] = split_result.query

        # Take the userinfo out of the URL and pass as 'auth' to treq so it can
        # be used for HTTP basic auth headers
        if 'auth' not in kwargs and userinfo is not None:
            # treq expects a 2-tuple (username, password)
            kwargs['auth'] = tuple(userinfo.split(':', 2))

        return uricompose(**compose_kwargs)