Urlpath
Object-oriented URL from `urllib.parse` and `pathlib`
Install / Use
/learn @brandonschabell/UrlpathREADME
URLPath
URLPath provides URL manipulator class that extends pathlib.PurePath.
Dependencies
Install
pip install urlpath
Examples
from urlpath import URL
# Create URL object
url = URL(
'https://username:password@secure.example.com:1234/path/to/file.ext?field1=1&field2=2&field1=3#fragment')
# Representation
assert str(url) == 'https://username:password@secure.example.com:1234/path/to/file.ext?field1=1&field2=2&field1=3#fragment'
assert url.as_uri() == 'https://username:password@secure.example.com:1234/path/to/file.ext?field1=1&field2=2&field1=3#fragment'
assert url.as_posix() == 'https://username:password@secure.example.com:1234/path/to/file.ext?field1=1&field2=2&field1=3#fragment'
# Access pathlib.PurePath compatible properties
assert url.drive == 'https://username:password@secure.example.com:1234'
assert url.root == '/'
assert url.anchor == 'https://username:password@secure.example.com:1234/'
assert url.path == '/path/to/file.ext'
assert url.name == 'file.ext'
assert url.suffix == '.ext'
assert url.suffixes == ['.ext']
assert url.stem == 'file'
assert url.parts == ('https://username:password@secure.example.com:1234/', 'path', 'to', 'file.ext')
assert str(url.parent) == 'https://username:password@secure.example.com:1234/path/to'
# Access scheme
assert url.scheme == 'https'
# Access netloc
assert url.netloc == 'username:password@secure.example.com:1234'
assert url.username == 'username'
assert url.password == 'password'
assert url.hostname == 'secure.example.com'
assert url.port == 1234
# Access query
assert url.query == 'field1=1&field2=2&field1=3'
assert url.form_fields == (('field1', '1'), ('field2', '2'), ('field1', '3'))
assert 'field1' in url.form
assert url.form.get_one('field1') == '1'
assert url.form.get_one('field3') is None
# Access fragment
assert url.fragment == 'fragment'
# Path operations
assert str(url / 'suffix') == 'https://username:password@secure.example.com:1234/path/to/file.ext/suffix'
assert str(url / '../../rel') == 'https://username:password@secure.example.com:1234/path/to/file.ext/../../rel'
assert str((url / '../../rel').resolve()) == 'https://username:password@secure.example.com:1234/path/rel'
assert str(url / '/') == 'https://username:password@secure.example.com:1234/'
assert str(url / 'http://example.com/') == 'http://example.com/'
# Replace components
assert str(url.with_scheme('http')) == 'http://username:password@secure.example.com:1234/path/to/file.ext?field1=1&field2=2&field1=3#fragment'
assert str(url.with_netloc('www.example.com')) == 'https://www.example.com/path/to/file.ext?field1=1&field2=2&field1=3#fragment'
assert str(url.with_userinfo('joe', 'pa33')) == 'https://joe:pa33@secure.example.com:1234/path/to/file.ext?field1=1&field2=2&field1=3#fragment'
assert str(url.with_hostinfo('example.com', 8080)) == 'https://username:password@example.com:8080/path/to/file.ext?field1=1&field2=2&field1=3#fragment'
assert str(url.with_fragment('new fragment')) == 'https://username:password@secure.example.com:1234/path/to/file.ext?field1=1&field2=2&field1=3#new fragment'
assert str(url.with_components(username=None, password=None, query='query', fragment='frag')) == 'https://secure.example.com:1234/path/to/file.ext?query#frag'
# Replace query
assert str(url.with_query({'field3': '3', 'field4': [1, 2, 3]})) == 'https://username:password@secure.example.com:1234/path/to/file.ext?field3=3&field4=1&field4=2&field4=3#fragment'
assert str(url.with_query(field3='3', field4=[1, 2, 3])) == 'https://username:password@secure.example.com:1234/path/to/file.ext?field3=3&field4=1&field4=2&field4=3#fragment'
assert str(url.with_query('query')) == 'https://username:password@secure.example.com:1234/path/to/file.ext?query#fragment'
assert str(url.with_query(None)) == 'https://username:password@secure.example.com:1234/path/to/file.ext#fragment'
# Amend query
assert str(url.with_query(field1='1').add_query(field2=2)) == 'https://username:password@secure.example.com:1234/path/to/file.ext?field1=1&field2=2#fragment'
HTTP requests
URLPath provides convenient methods for making HTTP requests:
from urlpath import URL
# GET request
url = URL('https://httpbin.org/get')
response = url.get()
assert response.status_code == 200
# POST request
url = URL('https://httpbin.org/post')
response = url.post(data={'key': 'value'})
assert response.status_code == 200
# DELETE request
url = URL('https://httpbin.org/delete')
response = url.delete()
assert response.status_code == 200
# PATCH request
url = URL('https://httpbin.org/patch')
response = url.patch(data={'key': 'value'})
assert response.status_code == 200
# PUT request
url = URL('https://httpbin.org/put')
response = url.put(data={'key': 'value'})
assert response.status_code == 200
Jail
from urlpath import URL
root = 'http://www.example.com/app/'
current = 'http://www.example.com/app/path/to/content'
url = URL(root).jailed / current
assert str(url / '/root') == 'http://www.example.com/app/root'
assert str((url / '../../../../../../root').resolve()) == 'http://www.example.com/app/root'
assert str(url / 'http://localhost/') == 'http://www.example.com/app/'
assert str(url / 'http://www.example.com/app/file') == 'http://www.example.com/app/file'
Trailing separator will be retained
from urlpath import URL
url = URL('http://www.example.com/path/with/trailing/sep/')
assert str(url).endswith('/')
assert url.trailing_sep == '/'
assert url.name == 'sep'
assert url.path == '/path/with/trailing/sep/'
assert url.parts[-1] == 'sep'
url = URL('http://www.example.com/path/without/trailing/sep')
assert not str(url).endswith('/')
assert url.trailing_sep == ''
assert url.name == 'sep'
assert url.path == '/path/without/trailing/sep'
assert url.parts[-1] == 'sep'
Related Skills
node-connect
342.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
342.0kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.7kCommit, push, and open a PR
