在我的程序中,我希望用户能够为CouchDB数据库指定一个URL。
我想为此网址的部分内容提供合理的默认值;例如,localhost,5984和mushin分别是host,port和path的默认值。
urlparse.urlparse返回一个元组子类,它也有属性访问器,但没有setter。
主机和端口(以及稍后的用户名和密码)是解析元组的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()
使用元组接口没有帮助,因为netloc没有拆分成用户名/密码/主机/端口组件,所以我仍然必须自己负责工作。
有没有更好的方法来解析URL,覆盖它的各个部分,并将新的URL重新组合在一起?
答案 0 :(得分:2)
我用来解决这个问题的片段:
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
,则不会强制您必须拥有用户名。但它完成了工作。
答案 1 :(得分:0)
对元组的操作副本使用urlparse.urlunparse。
parts参数可以是任何六项可迭代的。
p = urlparse.urlparse(url)
l = list(p)
l[4] = "foo=bar" # manipulate query parameters
urlparse.urlunparse(l)
答案 2 :(得分: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'
>>>
答案 3 :(得分:0)
您可以使用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()
方法。