An implementation of the URL Pattern Standard for Python written in Rust.
It's a thin wrapper of denoland/rust-urlpattern with PyO3 + Maturin.
It is useful on the server side when serving different pages based on the URL (a.k.a. routing). It provides pattern matching syntax like /users/:id, similar to route parameters in Express or Path-to-RegExp. You can use it as a foundation to build your own web server or framework.
On Linux/UNIX or macOS:
pip install urlpatternOn Windows:
py -m pip install urlpatternThis library aims to expose an interface as close as possible to the URL Pattern Standard, but some differences are unavoidable because it is designed for Python, not JavaScript. For the exact details, please refer to urlpattern.pyi.
Most JavaScript examples from Chrome for Developers and MDN can be adapted to Python without much difficulty.
from urlpattern import URLPattern
pattern = URLPattern("https://example.com/admin/*")
print(pattern.test("https://example.com/admin/main/"))
print(pattern.test("https://example.com/main/"))Output:
True
False
from urlpattern import URLPattern
pattern = URLPattern({"pathname": "/users/:id/"})
result = pattern.exec({"pathname": "/users/4163/"})
print(result["pathname"]["groups"]["id"])Output:
4163
from urlpattern import URLPattern
pattern = URLPattern("b", "https://example.com/a/")
print(pattern.test("a/b", "https://example.com/"))
print(pattern.test("b", "https://example.com/a/"))
print(
pattern.test({"pathname": "b", "baseURL": "https://example.com/a/"})
)Output:
True
True
True
from urlpattern import URLPattern
pattern = URLPattern("https://example.com/test")
print(pattern.test("https://example.com/test"))
print(pattern.test("https://example.com/TeST"))
pattern = URLPattern("https://example.com/test", {"ignoreCase": True})
print(pattern.test("https://example.com/test"))
print(pattern.test("https://example.com/TeST"))Output:
True
False
True
True
from wsgiref.simple_server import make_server
from urlpattern import URLPattern
user_id_pattern = URLPattern({"pathname": "/users/:id"})
def get_user_id(environ, start_response):
user_id = environ["result"]["pathname"]["groups"]["id"]
status = "200 OK"
response_headers = [("Content-type", "text/plain; charset=utf-8")]
start_response(status, response_headers)
return [f"{user_id=}".encode()]
def app(environ, start_response):
path = environ["PATH_INFO"]
method = environ["REQUEST_METHOD"]
if result := user_id_pattern.exec({"pathname": path}):
if method == "GET":
return get_user_id(environ | {"result": result}, start_response)
status = "404 Not Found"
response_headers = [("Content-type", "text/plain; charset=utf-8")]
start_response(status, response_headers)
return [b"Not Found"]
with make_server("", 8000, app) as httpd:
httpd.serve_forever()Due to limitations in the dependency denoland/rust-urlpattern, it may not support all features specified in the standard.
Check pytest.skip in tests/test_lib.py.
As seen in names like baseURL and hasRegExpGroups, this library does not follow Python's PEP 8 naming conventions. Instead, it follows the standard naming as closely as possible.
Like xml.dom, Python wrappers around web standards typically preserve the original camelCase rather than converting names to snake_case, and this library follows that convention as well.