4

在我的程序中,我希望用户能够指定 CouchDB 数据库的 url。

我想为这个 URL 的某些部分提供合理的默认值;例如,localhost、5984 和 mushin 分别是主机、端口和路径的默认值。

urlparse.urlparse 返回一个元组子类,它也有属性访问器,但没有设置器。

主机和端口(以及稍后的用户名和密码)是解析元组的 netloc 部分的属性。这些属性只是得到。所以这个对我来说很理想的代码失败了:

   try:
        jane = urlparse(args[0])
    except IndexError:
        self.stdout.write('Please give a database to replicate with.\n')
        return

    if not jane.hostname:
        jane.hostname = HOST
    if not jane.port:
        jane.port = PORT
    if not jane.path:
        jane.path = DB

    url = jane.geturl()

使用 tuple 接口并没有帮助,因为 netloc 没有拆分成用户名/密码/主机/端口组件,所以我还是要自己做首当其冲的工作。

有没有更好的方法来解析一个 URL,覆盖它的一部分,然后重新组合一个新的 URL?

4

4 回答 4

3

我用来解决这个问题的片段:

netloc_regex = re.compile(r"(?:([^:]+)(?::(.*))?@)?([^:]+)(?::([\d]+))?")
endpoint = # some value

scheme, netloc, path, params, query, fragment = urlparse(endpoint)
username, password, host, port = netloc_regex.search(netloc).groups()

# manipulate components here

auth = ":".join(filter(None, (username, password)))
address = ":".join(filter(None, (host, port)))
netloc = "@".join(filter(None, (auth, address)))
endpoint = urlunparse((scheme, netloc, path, params, query, fragment))

我预计会有错误和未捕获的情况,例如如果密码不是,它不会强制您必须有用户名None。但它可以完成工作。

于 2013-05-01T18:26:48.970 回答
1

您可以使用yurl库在一行中完成:

>>> import yurl
>>> user_url = yurl.URL('http://without.port/#hash')
>>> your_defaults = yurl.URL('//:33/default')  # or URL(port=33, path='/default')

>>> print user_url.replace(*map(lambda x: x or None, your_defaults))
http://without.port:33/default#hash

将空map部分(空字符串)替换None为然后作为参数传递给user_url.replace()方法。

于 2013-12-25T16:08:09.540 回答
0
class DbUrl(object):

    def __init__(self, db_url):
        split = urlparse.urlparse(db_url)
        self.scheme = split.scheme
        self.hostname = split.hostname
        self.port = split.port
        self.username = split.username
        self.password = split.password
        self.database = split.path.lstrip('/')

    def __str__(self):
        auth = ":".join(filter(None, (self.username, self.password)))
        address = ":".join(filter(None, (self.hostname, str(self.port))))
        netloc = "@".join(filter(None, (auth, address)))
        return urlparse.urlunparse((self.scheme, netloc, self.database, '', '', ''))

    def __repr__(self):
        return '%s(%s)' % (self.__class__.__name__, ', '.join(
            '%s=%r' % (attr_name, attr_value)
            for attr_name, attr_value in self.__dict__.iteritems()))

    def replace(self, **kwargs):
        db_url = copy.copy(self)
        for attr_name, attr_value in kwargs.iteritems():
            assert attr_name in db_url.__dict__, 'Unknown attribute'
            setattr(db_url, attr_name, attr_value)
        return db_url

和用法:

>>> DbUrl('postgresql://username:password@127.0.0.1:5433/postgres').replace(password='****')
DbUrl(username='username', password='****', hostname='127.0.0.1', database='postgres', scheme='postgresql', port=5433)
>>> str(DbUrl('postgresql://username:password@127.0.0.1:5433/postgres').replace(password='****'))
'postgresql://username:****@127.0.0.1:5433/postgres'
>>> str(DbUrl('postgresql://username:password@127.0.0.1:5433/postgres').replace(password=None))
'postgresql://username@127.0.0.1:5433/postgres'
>>> 
于 2013-11-29T13:21:26.903 回答
0

在元组的操纵副本上使用urlparse.urlunparse

部分参数可以是任何六项可迭代的。

p = urlparse.urlparse(url)
l = list(p)
l[4] = "foo=bar" # manipulate query parameters
urlparse.urlunparse(l)
于 2012-09-11T11:12:31.777 回答