From f3ca9f1254027cec1a49051b8de8f1a2eb5aadad Mon Sep 17 00:00:00 2001 From: Roman Tolkachyov Date: Mon, 26 Jan 2026 00:23:38 +0300 Subject: [PATCH 01/11] Improve python typings for PyCharm --- urlpattern.pyi | 52 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/urlpattern.pyi b/urlpattern.pyi index 1e2e266..811ba31 100644 --- a/urlpattern.pyi +++ b/urlpattern.pyi @@ -1,25 +1,55 @@ from typing_extensions import TypeAlias, TypedDict, overload -URLPatternInput: TypeAlias = str | URLPatternInit class URLPatternOptions(TypedDict, total=False): ignoreCase: bool + +class URLPatternInit(TypedDict, total=False): + protocol: str + username: str + password: str + hostname: str + port: str + pathname: str + search: str + hash: str + baseURL: str + class URLPattern: @overload def __init__( self, - input: URLPatternInput, + input: URLPatternInit, baseURL: str, options: URLPatternOptions | None = None, ): ... @overload def __init__( - self, input: URLPatternInput, options: URLPatternOptions | None = None + self, + input: str, + baseURL: str, + options: URLPatternOptions | None = None, ): ... - def test(self, input: URLPatternInput = {}, baseURL: str | None = None) -> bool: ... + @overload + def __init__( + self, input: URLPatternInit, options: URLPatternOptions | None = None + ): ... + @overload + def __init__( + self, input: str, options: URLPatternOptions | None = None + ): ... + @overload + def test(self, input: URLPatternInit, baseURL: str | None = None) -> bool: ... + @overload + def test(self, input: str, baseURL: str | None = None) -> bool: ... + @overload def exec( - self, input: URLPatternInput = {}, baseURL: str | None = None + self, input: URLPatternInit, baseURL: str | None = None + ) -> URLPatternResult | None: ... + @overload + def exec( + self, input: str, baseURL: str | None = None ) -> URLPatternResult | None: ... @property def protocol(self) -> str: ... @@ -38,19 +68,9 @@ class URLPattern: @property def hash(self) -> str: ... -class URLPatternInit(TypedDict, total=False): - protocol: str - username: str - password: str - hostname: str - port: str - pathname: str - search: str - hash: str - baseURL: str class URLPatternResult(TypedDict): - inputs: list[URLPatternInput] + inputs: list[str | URLPatternInit] protocol: URLPatternComponentResult username: URLPatternComponentResult From a0b43b01849ef63daf3d3cc32cf498e2a1d81a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=A9=EC=84=B1=EB=B2=94=20=28Bang=20Seongbeom=29?= Date: Sun, 25 Jan 2026 22:16:32 +0000 Subject: [PATCH 02/11] Update README.md --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 58cefd4..6616e5b 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ The URL Pattern Standard is a web standard for URL pattern matching. It is usefu It's a thin wrapper of [denoland/rust-urlpattern](https://github.com/denoland/rust-urlpattern) with [PyO3](https://github.com/PyO3/pyo3) + [Maturin](https://github.com/PyO3/maturin). +The naming conventions follow [the standard](https://urlpattern.spec.whatwg.org/) as closely as possible, similar to [xml.dom](https://docs.python.org/3/library/xml.dom.html). + ## Installation On Linux/UNIX or macOS: @@ -55,6 +57,16 @@ result = pattern.exec({"pathname": "/users/4163/"}) print(result["pathname"]["groups"]["id"]) # output: 4163 ``` +### `baseURL` + +```py +from urlpattern import URLPattern + +pattern = URLPattern({"pathname": "/admin/*"}, "https://example.com") +print(pattern.test({"pathname": "/admin/main/"}, "https://example.com")) # output: True +print(pattern.test("/admin/main/", "https://example.com")) # output: True +``` + ### `ignoreCase` ```py @@ -69,7 +81,7 @@ print(pattern.test("https://example.com/test")) # output: True print(pattern.test("https://example.com/TeST")) # output: True ``` -### Simple WSGI app +### A simple WSGI app ```py from wsgiref.simple_server import make_server From f97725065aaabb694e5ee1e6b20de336812f762e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=A9=EC=84=B1=EB=B2=94=20=28Bang=20Seongbeom=29?= Date: Mon, 26 Jan 2026 10:38:29 +0900 Subject: [PATCH 03/11] Add Free Threading in pyproject.toml --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 2f818e6..7df97b8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ classifiers = [ "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: Free Threading", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Rust", From 93d0eea46bbd81abc91e630f944d43428c40c20e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=A9=EC=84=B1=EB=B2=94=20=28Bang=20Seongbeom=29?= Date: Mon, 26 Jan 2026 10:41:05 +0900 Subject: [PATCH 04/11] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7df97b8..a4fdfc4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ classifiers = [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", @@ -22,7 +23,6 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", - "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: Free Threading", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", From a89988d1823aaa9d1e63be0c520469f9b8183993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=A9=EC=84=B1=EB=B2=94=20=28Bang=20Seongbeom=29?= Date: Mon, 26 Jan 2026 10:50:21 +0900 Subject: [PATCH 05/11] Remove extension-module feature --- pyproject.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a4fdfc4..ce28e98 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,3 @@ dynamic = ["version"] Homepage = "https://github.com/urlpattern/python-urlpattern" Repository = "https://github.com/urlpattern/python-urlpattern.git" Issues = "https://github.com/urlpattern/python-urlpattern/issues" - -[tool.maturin] -features = ["pyo3/extension-module"] From 5e17e935570484e0b85f80489a7f3883a8ae32d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=A9=EC=84=B1=EB=B2=94=20=28Bang=20Seongbeom=29?= Date: Mon, 26 Jan 2026 19:17:02 +0000 Subject: [PATCH 06/11] Fix return type annotations for URLPattern constructors --- urlpattern.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/urlpattern.pyi b/urlpattern.pyi index 1e2e266..17e9bd2 100644 --- a/urlpattern.pyi +++ b/urlpattern.pyi @@ -12,11 +12,11 @@ class URLPattern: input: URLPatternInput, baseURL: str, options: URLPatternOptions | None = None, - ): ... + ) -> None: ... @overload def __init__( self, input: URLPatternInput, options: URLPatternOptions | None = None - ): ... + ) -> None: ... def test(self, input: URLPatternInput = {}, baseURL: str | None = None) -> bool: ... def exec( self, input: URLPatternInput = {}, baseURL: str | None = None From b8d8fe13184b31f085f4e76d75941256f689d80c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=A9=EC=84=B1=EB=B2=94=20=28Bang=20Seongbeom=29?= Date: Mon, 26 Jan 2026 19:25:31 +0000 Subject: [PATCH 07/11] Update type annotations to support Python 3.8 --- urlpattern.pyi | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/urlpattern.pyi b/urlpattern.pyi index 17e9bd2..d157457 100644 --- a/urlpattern.pyi +++ b/urlpattern.pyi @@ -1,6 +1,8 @@ -from typing_extensions import TypeAlias, TypedDict, overload +from typing import Optional, TypedDict, Union, overload -URLPatternInput: TypeAlias = str | URLPatternInit +from typing_extensions import TypeAlias + +URLPatternInput: TypeAlias = Union[str, URLPatternInit] class URLPatternOptions(TypedDict, total=False): ignoreCase: bool @@ -11,16 +13,18 @@ class URLPattern: self, input: URLPatternInput, baseURL: str, - options: URLPatternOptions | None = None, + options: Optional[URLPatternOptions] = None, ) -> None: ... @overload def __init__( - self, input: URLPatternInput, options: URLPatternOptions | None = None + self, input: URLPatternInput, options: Optional[URLPatternOptions] = None ) -> None: ... - def test(self, input: URLPatternInput = {}, baseURL: str | None = None) -> bool: ... + def test( + self, input: URLPatternInput = {}, baseURL: Optional[str] = None + ) -> bool: ... def exec( - self, input: URLPatternInput = {}, baseURL: str | None = None - ) -> URLPatternResult | None: ... + self, input: URLPatternInput = {}, baseURL: Optional[str] = None + ) -> Optional[URLPatternResult]: ... @property def protocol(self) -> str: ... @property @@ -65,4 +69,4 @@ class URLPatternComponentResult(TypedDict): input: str groups: dict[str, str] -URLPatternCompatible: TypeAlias = str | URLPatternInit | URLPattern +URLPatternCompatible: TypeAlias = Union[str, URLPatternInit, URLPattern] From 74ab0bd701df361c6de18a41db2e2bc6d66a665b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=A9=EC=84=B1=EB=B2=94=20=28Bang=20Seongbeom=29?= Date: Mon, 26 Jan 2026 19:53:54 +0000 Subject: [PATCH 08/11] Make input parameter optional --- urlpattern.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/urlpattern.pyi b/urlpattern.pyi index d157457..2c9d4c1 100644 --- a/urlpattern.pyi +++ b/urlpattern.pyi @@ -17,7 +17,7 @@ class URLPattern: ) -> None: ... @overload def __init__( - self, input: URLPatternInput, options: Optional[URLPatternOptions] = None + self, input: URLPatternInput = {}, options: Optional[URLPatternOptions] = None ) -> None: ... def test( self, input: URLPatternInput = {}, baseURL: Optional[str] = None From 402b8795503fb4f90e425edca5b9bc3c1f996277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=A9=EC=84=B1=EB=B2=94=20=28Bang=20Seongbeom=29?= Date: Mon, 26 Jan 2026 19:54:31 +0000 Subject: [PATCH 09/11] Change default value of options parameter to an empty dict --- urlpattern.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/urlpattern.pyi b/urlpattern.pyi index 2c9d4c1..e452c0b 100644 --- a/urlpattern.pyi +++ b/urlpattern.pyi @@ -13,11 +13,11 @@ class URLPattern: self, input: URLPatternInput, baseURL: str, - options: Optional[URLPatternOptions] = None, + options: Optional[URLPatternOptions] = {}, ) -> None: ... @overload def __init__( - self, input: URLPatternInput = {}, options: Optional[URLPatternOptions] = None + self, input: URLPatternInput = {}, options: Optional[URLPatternOptions] = {} ) -> None: ... def test( self, input: URLPatternInput = {}, baseURL: Optional[str] = None From e4f6c0554f34e4ac83cce3fa8f8975f46caf21c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=A9=EC=84=B1=EB=B2=94=20=28Bang=20Seongbeom=29?= Date: Tue, 27 Jan 2026 05:10:39 +0900 Subject: [PATCH 10/11] Add missing default value --- urlpattern.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/urlpattern.pyi b/urlpattern.pyi index fd14f52..73fb90e 100644 --- a/urlpattern.pyi +++ b/urlpattern.pyi @@ -42,7 +42,7 @@ class URLPattern: def __init__(self, input: str, options: None) -> None: ... @overload def __init__( - self, input: URLPatternInit, options: URLPatternOptions = {} + self, input: URLPatternInit = {}, options: URLPatternOptions = {} ) -> None: ... @overload def __init__(self, input: URLPatternInit, options: None) -> None: ... From f41c7779630dfa0e60f00a558628edf7b90866c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=A9=EC=84=B1=EB=B2=94=20=28Bang=20Seongbeom=29?= Date: Mon, 26 Jan 2026 20:22:53 +0000 Subject: [PATCH 11/11] Bump to 0.1.8 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b0a624..95c208f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -280,7 +280,7 @@ dependencies = [ [[package]] name = "python-urlpattern" -version = "0.1.7" +version = "0.1.8" dependencies = [ "pyo3", "urlpattern", diff --git a/Cargo.toml b/Cargo.toml index 3d3a647..bafa905 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "python-urlpattern" -version = "0.1.7" +version = "0.1.8" authors = ["방성범 (Bang Seongbeom) "] edition = "2024" description = "An implementation of the URL Pattern Standard for Python written in Rust."