Skip to content

urlpattern/python-urlpattern

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

140 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

urlpattern

PyPI - Version PyPI - Python Version Ruff CI

An implementation of the URL Pattern Standard for Python written in Rust.

Introduction

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.

Installation

On Linux/UNIX or macOS:

pip install urlpattern

On Windows:

py -m pip install urlpattern

Usage

This 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.

test

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

exec

from urlpattern import URLPattern

pattern = URLPattern({"pathname": "/users/:id/"})
result = pattern.exec({"pathname": "/users/4163/"})
print(result["pathname"]["groups"]["id"])

Output:

4163

baseURL

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

ignoreCase

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

A simple WSGI app

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()

Limitations

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.

Why camelCase?

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.

About

An implementation of the URL Pattern Standard for Python written in Rust.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors